<template>
	<!-- 微信小程序 -->
	<!-- #ifdef MP-WEIXIN -->
	<view class="engineering-canvas">
		<canvas id="mainCanvas" type="2d" class="canvas-layer"
			:style="{ width: canvasWidth + 'px', height: canvasHeight + 'px' }" @touchstart="handleTouchStart"
			@touchmove.prevent="handleTouchMove" @touchend="handleTouchEnd"></canvas>
		<cover-view class="control-buttons" prevent-default>
			<cover-view class="btn" @click="subData">提交</cover-view>
			<!-- <cover-view class="btn" @click="exportData">导出</cover-view> -->
			<cover-view class="btn" @click="undo">撤回</cover-view>
		</cover-view>
		<cover-view class="data-operate" v-if="selectData" prevent-default>
			<template v-if="selectData.type === 'line' || selectData.type === 'arc'">
				<cover-view class="ope" @click="modData">
					<cover-view class="ope-icon">
						<cover-image src="https://renovationcdn.jiachuangnet.com/static/edit.png"></cover-image>
					</cover-view>
					<cover-view class="ope-name">编辑</cover-view>
				</cover-view>
				<cover-view class="ope" @click="convertToArc" v-if="selectData.type === 'line'">
					<cover-view class="ope-icon">
						<cover-image src="https://renovationcdn.jiachuangnet.com/static/arcLine.png"></cover-image>
					</cover-view>
					<cover-view class="ope-name">转弧线</cover-view>
				</cover-view>
				<cover-view class="ope" @click="convertToLine" v-if="selectData.type === 'arc'">
					<cover-view class="ope-icon">
						<cover-image src="https://renovationcdn.jiachuangnet.com/static/line.png"></cover-image>
					</cover-view>
					<cover-view class="ope-name">转直线</cover-view>
				</cover-view>
			</template>
			<cover-view class="ope" @click="copyItem" v-if="selectData.class">
				<cover-view class="ope-icon">
					<!-- <cover-image src="https://renovationcdn.jiachuangnet.com/static/copy.png"></cover-image> -->
				</cover-view>
				<cover-view class="ope-name">复制</cover-view>
			</cover-view>
			<cover-view class="ope" @click="rotateItem" v-if="selectData.class">
				<cover-view class="ope-icon">
					<cover-image src="https://renovationcdn.jiachuangnet.com/static/rotate.png"></cover-image>
				</cover-view>
				<cover-view class="ope-name">旋转</cover-view>
			</cover-view>
			<cover-view class="ope" @click="deleteItem">
				<cover-view class="ope-icon">
					<!-- <cover-image src="https://renovationcdn.jiachuangnet.com/static/delete.png"></cover-image> -->
				</cover-view>
				<cover-view class="ope-name">删除</cover-view>
			</cover-view>
		</cover-view>
		<cover-view class="data-main-set" v-if="modMainData" prevent-default>
			<cover-view class="status-type-list">
				<cover-view class="single-status" :class="{ 'status-active': statusSelect === 1 }"
					@click="statusSelect = 1">
					墙厚
				</cover-view>
				<cover-view class="single-status" :class="{ 'status-active': statusSelect === 2 }"
					@click="statusSelect = 2">
					墙长
				</cover-view>
				<cover-view class="single-status" :class="{ 'status-active': statusSelect === 3 }"
					@click="statusSelect = 3">
					属性
				</cover-view>
			</cover-view>
			<cover-view class="wall-thick" v-if="statusSelect === 1">
				<cover-view class="wall-thick-input">
					<cover-view>墙厚</cover-view>
					<cover-view>{{ parseInt(inputNum ? inputNum : modMainData.lineHeight) }}cm</cover-view>
				</cover-view>
			</cover-view>
			<cover-view class="wall-thick" v-if="statusSelect === 2">
				<cover-view class="wall-thick-input">
					<cover-view>墙长</cover-view>
					<cover-view>{{ parseInt(inputNum ? inputNum : modMainData.lineWidth) }}cm</cover-view>
				</cover-view>
			</cover-view>
			<cover-view class="wall-thick-calendar" v-if="statusSelect === 1 || statusSelect === 2">
				<cover-view class="cal-num">
					<cover-view class="single-num" v-for="n in [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]" :key="n"
						@click="addNum(n)" :style="{width: n == 0 ? '100%' : ''}">
						<cover-view class="cal-btn">{{ n }}</cover-view>
					</cover-view>
				</cover-view>
				<cover-view class="cal-confirm">
					<cover-view class="cal-del" @click="delNum">
						<cover-view class="cal-btn">
							<cover-image src="https://renovationcdn.jiachuangnet.com/static/del.png"></cover-image>
						</cover-view>
					</cover-view>
					<cover-view class="cal-sure" @click="sureNum">
						<cover-view class="cal-btn"
							style="height: 100%; background: orange; color: #fff">确定</cover-view>
					</cover-view>
				</cover-view>
			</cover-view>
			<cover-view class="wall-list" v-if="statusSelect === 3">
				<cover-view class="wall" :class="{ 'active-wall': modMainData.wallType === 1 || !modMainData.wallType }"
					@click="changeWall(1)">
					<cover-view class="wallPic">
						<cover-image src="https://renovationcdn.jiachuangnet.com/static/wallType1.png"
							style="width: 100%" mode="widthFix"></cover-image>
						<cover-image class="selected-wall"
							src="https://renovationcdn.jiachuangnet.com/static/selected.png"
							v-if="modMainData.wallType === 1 || !modMainData.wallType"></cover-image>
					</cover-view>
					<cover-view class="wallDesc">砌体墙</cover-view>
				</cover-view>
				<cover-view class="wall" :class="{ 'active-wall': modMainData.wallType === 2 }" @click="changeWall(2)">
					<cover-view class="wallPic">
						<cover-image src="https://renovationcdn.jiachuangnet.com/static/wallType2.png"
							style="width: 100%" mode="widthFix"></cover-image>
						<cover-image class="selected-wall"
							src="https://renovationcdn.jiachuangnet.com/static/selected.png"
							v-if="modMainData.wallType === 2"></cover-image>
					</cover-view>
					<cover-view class="wallDesc">剪力墙</cover-view>
				</cover-view>
				<cover-view class="wall" :class="{ 'active-wall': modMainData.wallType === 3 }" @click="changeWall(3)">
					<cover-view class="wallPic">
						<cover-image src="https://renovationcdn.jiachuangnet.com/static/wallType2.png"
							style="width: 100%" mode="widthFix"></cover-image>
						<cover-image class="selected-wall"
							src="https://renovationcdn.jiachuangnet.com/static/selected.png"
							v-if="modMainData.wallType === 3"></cover-image>
					</cover-view>
					<cover-view class="wallDesc">玻璃墙</cover-view>
				</cover-view>
			</cover-view>
		</cover-view>
		<cover-view class="bot-btn-list" prevent-default>
			<cover-view class="bot-btn" @click="resetPoint" v-if="crossesIn">
				<cover-view class="btn-icon">
					<cover-image src="https://renovationcdn.jiachuangnet.com/static/reset.png"></cover-image>
				</cover-view>
				<cover-view>重置光标</cover-view>
			</cover-view>
			<cover-view class="reset-mask" :style="{height: !crossesIn ? '100%' : '0'}"
				style="position: fixed; width: 100%; left: 0; top: 0" @touchstart.prevent="handleSetCrossStart"
				@touchmove.prevent="handleSetCrossMove" @touchend.prevent="handleSetCrossEnd">
				<cover-view class="bot-btn" prevent-default v-if="!crossesIn"
					style="position: absolute; bottom: 50rpx; right: 180rpx">
					<cover-view class="btn-icon">
						<cover-image src="https://renovationcdn.jiachuangnet.com/static/point.png"></cover-image>
					</cover-view>
					<cover-view>光标拖动到墙体</cover-view>
				</cover-view>
			</cover-view>
			<cover-view class="bot-btn" @click="addItems">
				<cover-view class="btn-icon">
					<cover-image src="https://renovationcdn.jiachuangnet.com/static/add.png"></cover-image>
				</cover-view>
				<cover-view>添加</cover-view>
			</cover-view>
		</cover-view>
		<cover-view v-if="addItemsShow" @click.prevent="addItemsShow = false"
			:style="{ height: addItemsShow ? '100%' : '0' }"
			style="width: 100%; height: 100%; background: transparent; position: fixed; left: 0; top: 0; z-index: 99"
			@touchstart="touchStartAll" @touchmove="touchMoveAll" @touchend="touchEndAll">
			<cover-view class="add-item-list" prevent-default @click.stop="()=>{}">
				<cover-view class="tab-scroll" scroll-x prevent-default>
					<cover-view class="tab-list" prevent-default>
						<cover-view :class="{ 'tab-item': true, 'active-item': addItemType === 'door' }"
							@click.stop="addItemType = 'door'" prevent-default>
							门
						</cover-view>
						<cover-view :class="{ 'tab-item': true, 'active-item': addItemType === 'window' }"
							@click.stop="addItemType = 'window'" prevent-default>
							窗
						</cover-view>
						<cover-view :class="{ 'tab-item': true, 'active-item': addItemType === 'pillar' }"
							@click.stop="addItemType = 'pillar'" prevent-default>
							梁柱管
						</cover-view>
					</cover-view>
				</cover-view>
				<cover-view class="tab-item-main" prevent-default>
					<cover-view class="add-item" v-for="(data, idx) in addItemList[addItemType]" :key="idx"
						prevent-default @touchstart="(e) => handleAddItemStart(e, addItemType, data)"
						@touchmove="(e) => handleAddItemMove(e, addItemType, data)"
						@touchend="(e) => handleAddItemEnd(e, addItemType, data)">
						<cover-view class="add-inner">
							<cover-view class="add-item-icon">
								<cover-image :src="
                    addItemType !== 'window'
                      ? `https://renovationcdn.jiachuangnet.com/static/${addItemType}/${data.type}.png`
                      : `https://renovationcdn.jiachuangnet.com/static/window.png`
                  "></cover-image>
							</cover-view>
							<cover-view class="add-item-name">{{ data.name }}</cover-view>
						</cover-view>
					</cover-view>
				</cover-view>
			</cover-view>
		</cover-view>
	</view>
	<!-- #endif -->

	<!-- 安卓平台 -->
	<!-- #ifdef APP-PLUS -->
	<view class="engineering-canvas">
		<canvas id="mainCanvas" canvas-id="mainCanvas" type="2d" class="canvas-layer"
			:style="{ width:'100vw', height: '100vh' }" @touchstart="handleTouchStart"
			@touchmove.prevent="handleTouchMove" @touchend="handleTouchEnd"></canvas>
		<view class="control-buttons" prevent-default>
			<view class="btn" @click="subData">提交</view>
			<!-- <view class="btn" @click="exportData">导出</view> -->
			<view class="btn" @click="undo">撤回</view>
		</view>
		<view class="data-operate" v-if="selectData" prevent-default>
			<template v-if="selectData.type === 'line' || selectData.type === 'arc'">
				<view class="ope" @click="modData">
					<view class="ope-icon">
						<image src="https://renovationcdn.jiachuangnet.com/static/edit.png" mode="widthFix"></image>
					</view>
					<view class="ope-name">编辑</view>
				</view>
				<view class="ope" @click="convertToArc" v-if="selectData.type === 'line'">
					<view class="ope-icon">
						<image src="https://renovationcdn.jiachuangnet.com/static/arcLine.png" mode="widthFix"></image>
					</view>
					<view class="ope-name">转弧线</view>
				</view>
				<view class="ope" @click="convertToLine" v-if="selectData.type === 'arc'">
					<view class="ope-icon">
						<image src="https://renovationcdn.jiachuangnet.com/static/line.png" mode="widthFix"></image>
					</view>
					<view class="ope-name">转直线</view>
				</view>
			</template>
			<view class="ope" @click="copyItem" v-if="selectData.class">
				<view class="ope-icon">
					<!-- <image src="https://renovationcdn.jiachuangnet.com/static/copy.png" mode="widthFix"></image> -->
				</view>
				<view class="ope-name">复制</view>
			</view>
			<view class="ope" @click="rotateItem" v-if="selectData.class">
				<view class="ope-icon">
					<image src="https://renovationcdn.jiachuangnet.com/static/rotate.png" mode="widthFix"></image>
				</view>
				<view class="ope-name">旋转</view>
			</view>
			<view class="ope" @click="deleteItem">
				<view class="ope-icon">
					<!-- <image src="https://renovationcdn.jiachuangnet.com/static/delete.png" mode="widthFix"></image> -->
				</view>
				<view class="ope-name">删除</view>
			</view>
		</view>
		<view class="data-main-set" v-if="modMainData" prevent-default>
			<view class="status-type-list">
				<view class="single-status" :class="{ 'status-active': statusSelect === 1 }" @click="statusSelect = 1">
					墙厚
				</view>
				<view class="single-status" :class="{ 'status-active': statusSelect === 2 }" @click="statusSelect = 2">
					墙长
				</view>
				<view class="single-status" :class="{ 'status-active': statusSelect === 3 }" @click="statusSelect = 3">
					属性
				</view>
			</view>
			<view class="wall-thick" v-if="statusSelect === 1">
				<view class="wall-thick-input">
					<view>墙厚</view>
					<view>{{ parseInt(inputNum ? inputNum : modMainData.lineHeight) }}cm</view>
				</view>
			</view>
			<view class="wall-thick" v-if="statusSelect === 2">
				<view class="wall-thick-input">
					<view>墙长</view>
					<view>{{ parseInt(inputNum ? inputNum : modMainData.lineWidth) }}cm</view>
				</view>
			</view>
			<view class="wall-thick-calendar" v-if="statusSelect === 1 || statusSelect === 2">
				<view class="cal-num">
					<view class="single-num" v-for="n in [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]" :key="n" @click="addNum(n)"
						:style="{width: n == 0 ? '100%' : ''}">
						<view class="cal-btn">{{ n }}</view>
					</view>
				</view>
				<view class="cal-confirm">
					<view class="cal-del" @click="delNum">
						<view class="cal-btn">
							<image src="https://renovationcdn.jiachuangnet.com/static/del.png" mode="widthFix"></image>
						</view>
					</view>
					<view class="cal-sure" @click="sureNum">
						<view class="cal-btn" style="height: 100%; background: orange; color: #fff">确定</view>
					</view>
				</view>
			</view>
			<view class="wall-list" v-if="statusSelect === 3">
				<view class="wall" :class="{ 'active-wall': modMainData.wallType === 1 || !modMainData.wallType }"
					@click="changeWall(1)">
					<view class="wallPic">
						<image src="https://renovationcdn.jiachuangnet.com/static/wallType1.png" style="width: 100%"
							mode="widthFix"></image>
						<image class="selected-wall" src="https://renovationcdn.jiachuangnet.com/static/selected.png"
							v-if="modMainData.wallType === 1 || !modMainData.wallType" mode="widthFix"></image>
					</view>
					<view class="wallDesc">砌体墙</view>
				</view>
				<view class="wall" :class="{ 'active-wall': modMainData.wallType === 2 }" @click="changeWall(2)">
					<view class="wallPic">
						<image src="https://renovationcdn.jiachuangnet.com/static/wallType2.png" style="width: 100%"
							mode="widthFix"></image>
						<image class="selected-wall" src="https://renovationcdn.jiachuangnet.com/static/selected.png"
							v-if="modMainData.wallType === 2" mode="widthFix"></image>
					</view>
					<view class="wallDesc">剪力墙</view>
				</view>
				<view class="wall" :class="{ 'active-wall': modMainData.wallType === 3 }" @click="changeWall(3)">
					<view class="wallPic">
						<image src="https://renovationcdn.jiachuangnet.com/static/wallType2.png" style="width: 100%"
							mode="widthFix"></image>
						<image class="selected-wall" src="https://renovationcdn.jiachuangnet.com/static/selected.png"
							v-if="modMainData.wallType === 3" mode="widthFix"></image>
					</view>
					<view class="wallDesc">玻璃墙</view>
				</view>
			</view>
		</view>
		<view class="bot-btn-list" prevent-default>
			<view class="bot-btn" @click="resetPoint" v-if="crossesIn">
				<view class="btn-icon">
					<image src="https://renovationcdn.jiachuangnet.com/static/reset.png" mode="widthFix"></image>
				</view>
				<view>重置光标</view>
			</view>
			<view class="reset-mask" :style="{height: !crossesIn ? '100%' : '0'}"
				style="position: fixed; width: 100%; left: 0; top: 0" @touchstart.prevent="handleSetCrossStart"
				@touchmove.prevent="handleSetCrossMove" @touchend.prevent="handleSetCrossEnd">
				<view class="bot-btn" prevent-default v-if="!crossesIn"
					style="position: absolute; bottom: 50rpx; right: 180rpx">
					<view class="btn-icon">
						<image src="https://renovationcdn.jiachuangnet.com/static/point.png" mode="widthFix"></image>
					</view>
					<view>光标拖动到墙体</view>
				</view>
			</view>
			<view class="bot-btn" @click="addItems">
				<view class="btn-icon">
					<image src="https://renovationcdn.jiachuangnet.com/static/add.png" mode="widthFix"></image>
				</view>
				<view>添加</view>
			</view>
		</view>
		<view v-if="addItemsShow" @click.prevent="addItemsShow = false" :style="{ height: addItemsShow ? '100%' : '0' }"
			style="width: 100%; height: 100%; background: transparent; position: fixed; left: 0; top: 0; z-index: 99"
			@touchstart="touchStartAll" @touchmove="touchMoveAll" @touchend="touchEndAll">
			<view class="add-item-list" prevent-default @click.stop="()=>{}">
				<view class="tab-scroll" scroll-x prevent-default>
					<view class="tab-list" prevent-default>
						<view :class="{ 'tab-item': true, 'active-item': addItemType === 'door' }"
							@click.stop="addItemType = 'door'" prevent-default>
							门
						</view>
						<view :class="{ 'tab-item': true, 'active-item': addItemType === 'window' }"
							@click.stop="addItemType = 'window'" prevent-default>
							窗
						</view>
						<view :class="{ 'tab-item': true, 'active-item': addItemType === 'pillar' }"
							@click.stop="addItemType = 'pillar'" prevent-default>
							梁柱管
						</view>
					</view>
				</view>
				<view class="tab-item-main" prevent-default>
					<view class="add-item" v-for="(data, idx) in addItemList[addItemType]" :key="idx" prevent-default
						@touchstart="(e) => handleAddItemStart(e, addItemType, data)"
						@touchmove="(e) => handleAddItemMove(e, addItemType, data)"
						@touchend="(e) => handleAddItemEnd(e, addItemType, data)">
						<view class="add-inner">
							<view class="add-item-icon">
								<image :src="
                    addItemType !== 'window'
                      ? `https://renovationcdn.jiachuangnet.com/static/${addItemType}/${data.type}.png`
                      : `https://renovationcdn.jiachuangnet.com/static/window.png`
                  " mode="widthFix"></image>
							</view>
							<view class="add-item-name">{{ data.name }}</view>
						</view>
					</view>
				</view>
			</view>
		</view>
	</view>
	<!-- #endif -->
</template>

<script>
	import {
		snapToGrid,
		worldToScreen,
		screenToWorld,
		distance,
		closestPointOnLine,
		snapToWallEndpoint
	} from './utils.js';

	export default {
		data() {
			return {
				isDraggingArcControl: false, // 标志是否拖拽弧线控制点

				isDraggingControlPoint: false, // 新增标志用于判断是否拖拽控制点
				draggedControlPoint: null, // 记录当前拖拽的控制点
				canvasWidth: 300,
				canvasHeight: 300,
				gridSize: 10,
				offsetX: 0,
				offsetY: 0,
				scale: 1,
				minScale: 0.1,
				maxScale: 5,
				dpr: 1,
				canvasRect: {
					left: 0,
					top: 0
				},
				mainCtx: null,
				lastDrawTime: 0,
				drawPending: false,
				isDragging: false,
				isDraggingCrosshair: false,
				isDrawing: false,
				startX: 0,
				startY: 0,
				crosshairX: 0,
				crosshairY: 0,
				tempEndPoint: null,
				selectedLine: null,
				linePoints: [],
				crossesIn: true,
				resetSelf: true,
				addData: null,
				defaultData: null,
				focusLine: null,
				selectData: null,
				modMainData: null,
				addItemsShow: null,
				waitCloseLine: false,
				addItemType: 'door',
				statusSelect: 1,
				inputNum: null,
				initialPinchDistance: null,
				pinchCenter: {
					x: 0,
					y: 0
				},
				addDoorPos: null,
				addWindowPos: null,
				addPillarPos: null,
				addItemList: {
					door: [{
							type: 1,
							name: '普通门',
							width: 20
						},
						{
							type: 2,
							name: '双开门',
							width: 40
						},
					],
					window: [{
						type: 1,
						name: '普通窗',
						width: 40,
						height: 10
					}],
					pillar: [{
							type: 1,
							name: '方柱',
							width: 40,
							height: 40
						},
						{
							type: 2,
							name: '圆柱',
							width: 20
						},
					],
				},
				doors: [],
				windows: [],
				pillars: [],
				sureRoom: [],
				showCrosshair: true,
				historyStack: [],
			};
		},
		// ========== 生命周期 ==========
		onLoad(options) {
		  // 微信/小程序端保持原样
		  // #ifndef APP-PLUS
		  if (options.id != 'a') {
		    this.getData(options.id);
		  }
		  // #endif
		
		  // Android-App 端提前拿系统信息
		  // #ifdef APP-PLUS
		  this.initSystemInfo_Android().then(() => {
		    // 安卓端数据准备好后再请求业务数据
		    if (options.id != 'a') {
		      this.getData(options.id);
		    }
		  });
		  // #endif
		},
		
		onReady() {
		  // 微信端保持原链路
		  // #ifndef APP-PLUS
		  this.initSystemInfo().then(() => {});
		  // #endif
		
		  // 安卓端在 onReady 里建 canvas
		  // #ifdef APP-PLUS
		  this.initCanvas_Android();
		  // #endif
		},
		methods: {
			// #ifdef APP-PLUS
			async initSystemInfo_Android() {
			  return new Promise((resolve) => {
			    plus.device.getInfo({
			      success: (dev) => {
			        // 可用屏幕 px（不含导航栏）
			        const dw = plus.screen.resolutionWidth;
			        const dh = plus.screen.resolutionHeight;
			        // 像素比
			        this.dpr = plus.screen.scale;
					console.log(dw,dh)
			        this.canvasWidth  = dw;
			        this.canvasHeight = dh;
			        this.crosshairX   = Math.round(dw / 2 / this.scale / this.gridSize) * this.gridSize;
			        this.crosshairY   = Math.round(dh / 2 / this.scale / this.gridSize) * this.gridSize;
			
			        resolve();
			      },
			      fail: () => {
			        // 降级
			        this.fallbackInit();
			        resolve();
			      }
			    });
			  });
			},
			
			initCanvas_Android() {
			   this.$nextTick(() => {
			      // 2. 直接复用小程序的接口
			      const ctx = uni.createCanvasContext('mainCanvas', this);
			      this.mainCtx = ctx;
			  
			      // 3. 记录一下画布在屏幕上的绝对位置（后面坐标转换用）
			      const query = uni.createSelectorQuery().in(this);
			      query.select('#mainCanvas').boundingClientRect();
			      query.exec((res) => {
			        if (res && res[0]) {
			          this.canvasRect = {
			            left: res[0].left,
			            top:  res[0].top
			          };
			        }
			        // 4. 开始首次绘制
			        this.drawAll();
			      });
			    });
			},
			// #endif
			
			// ========== 公共降级 ==========
			fallbackInit() {
			  this.canvasWidth  = 300;
			  this.canvasHeight = 300;
			  this.dpr          = 1;
			  this.crosshairX   = Math.round(150 / this.scale / this.gridSize) * this.gridSize;
			  this.crosshairY   = Math.round(150 / this.scale / this.gridSize) * this.gridSize;
			  // #ifndef APP-PLUS
			  this.initCanvas();
			  // #endif
			  // #ifdef APP-PLUS
			  this.initCanvas_Android();
			  // #endif
			},
			saveState() {
				const lastState = JSON.stringify(this.historyStack[this.historyStack.length - 1])

				const state = {
					sureRoom: JSON.parse(JSON.stringify(this.sureRoom)),
					doors: JSON.parse(JSON.stringify(this.doors)),
					windows: JSON.parse(JSON.stringify(this.windows)),
					pillars: JSON.parse(JSON.stringify(this.pillars)),
					crosshairX: this.crosshairX,
					crosshairY: this.crosshairY
				};
				if (JSON.stringify(state) == lastState) {
					return
				}
				const lastWall = this.sureRoom[0]?.[this.sureRoom[0].length - 1];
				const lastEnd = lastWall ? lastWall.end : {
					x: this.crosshairX,
					y: this.crosshairY
				};
				state.crosshairX = lastEnd.x;
				state.crosshairY = lastEnd.y;

				this.historyStack.push(state);
				console.log('保存状态：', state); // ✅ 调试用
			},

			undo() {
				if (this.historyStack.length === 0) return;
				console.log('历史栈内容：', this.historyStack);
				const lastState = this.historyStack.pop();
				console.log('撤回前 doors：', this.doors);
				console.log('撤回后 doors：', lastState.doors);
				this.sureRoom = JSON.parse(JSON.stringify(lastState.sureRoom));
				this.doors = JSON.parse(JSON.stringify(lastState.doors));
				this.windows = JSON.parse(JSON.stringify(lastState.windows));
				this.pillars = JSON.parse(JSON.stringify(lastState.pillars));

				// ✅ 默认恢复保存的十字坐标
				this.crosshairX = lastState.crosshairX;
				this.crosshairY = lastState.crosshairY;

				// ✅ 如果还有墙体，设置为最后一段墙的终点
				if (this.sureRoom[0] && this.sureRoom[0].length > 0) {
					const lastWall = this.sureRoom[0][this.sureRoom[0].length - 1];
					this.crosshairX = lastWall.end.x;
					this.crosshairY = lastWall.end.y;
				} else {
					// ✅ 墙体被清空，回到画布中心（初始点位）
					const centerX = Math.round(this.canvasWidth / 2 / this.scale / this.gridSize) * this.gridSize;
					const centerY = Math.round(this.canvasHeight / 2 / this.scale / this.gridSize) * this.gridSize;
					this.crosshairX = centerX;
					this.crosshairY = centerY;
				}
				this.showCrosshair = true
				this.selectData = null;
				this.selectedLine = null;
				this.modMainData = null;
				console.log('撤回后状态：', {
					sureRoom: this.sureRoom,
					doors: this.doors,
					windows: this.windows,
					pillars: this.pillars,
				});
				this.$nextTick(() => {
					setTimeout(() => this.drawAll(), 50);
				});

				// uni.showToast({ title: '撤回成功', icon: 'success' });
			},
			async initSystemInfo() {
				try {
					const res = await uni.getSystemInfo();
					// 横向显示约30个网格，1网格=10cm，换算为像素
					this.canvasWidth = res.windowWidth;
					this.canvasHeight = res.windowHeight;
					this.dpr = res.pixelRatio;
					// 每个网格10像素，scale=1时1cm=1像素
					// 将十字星标置于画布中心
					this.crosshairX = Math.round(this.canvasWidth / 2 / this.scale / this.gridSize) * this.gridSize;
					this.crosshairY = Math.round(this.canvasHeight / 2 / this.scale / this.gridSize) * this.gridSize;
					this.$nextTick(() => {
						this.initCanvas();
					});
				} catch (err) {
					console.error('获取系统信息失败:', err);
					this.canvasWidth = 300; // 默认30网格
					this.canvasHeight = 300;
					this.dpr = 1;
					// 默认情况下的中心位置
					this.crosshairX = Math.round(this.canvasWidth / 2 / this.scale / this.gridSize) * this.gridSize;
					this.crosshairY = Math.round(this.canvasHeight / 2 / this.scale / this.gridSize) * this.gridSize;
					this.initCanvas();
				}
			},
			initCanvas() {
				this.createSelectorQuery()
					.select('#mainCanvas')
					.node(({
						node: canvas
					}) => {
						this.mainCtx = canvas.getContext('2d');
						canvas.width = this.canvasWidth * this.dpr;
						canvas.height = this.canvasHeight * this.dpr;
						this.mainCtx.scale(this.dpr, this.dpr);
						this.createSelectorQuery()
							.select('#mainCanvas')
							.boundingClientRect(rect => {
								this.canvasRect = {
									left: rect.left,
									top: rect.top
								};
								this.drawAll();
							})
							.exec();
					})
					.exec();
			},
			drawArrowhead(ctx, fromX, fromY, toX, toY, size) {
				const dx = toX - fromX;
				const dy = toY - fromY;
				const angle = Math.atan2(dy, dx);
				const headlen = size;
				ctx.beginPath();
				ctx.moveTo(toX, toY);
				ctx.lineTo(
					toX - headlen * Math.cos(angle - Math.PI / 6),
					toY - headlen * Math.sin(angle - Math.PI / 6)
				);
				ctx.moveTo(toX, toY);
				ctx.lineTo(
					toX - headlen * Math.cos(angle + Math.PI / 6),
					toY - headlen * Math.sin(angle + Math.PI / 6)
				);
				ctx.stroke();
			},
			drawAll() {
				if (!this.mainCtx) return;
				const now = Date.now();
				if (now - this.lastDrawTime < 16) {
					if (!this.drawPending) {
						this.drawPending = true;
						setTimeout(() => {
							this.drawAll();
							this.drawPending = false;
						}, 16);
					}
					return;
				}
				this.lastDrawTime = now;
				this.mainCtx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
				this.mainCtx.save();
				this.mainCtx.scale(this.scale, this.scale);
				this.mainCtx.translate(this.offsetX / this.scale, this.offsetY / this.scale);

				// 绘制网格
				const visibleLeft = -this.offsetX / this.scale;
				const visibleRight = visibleLeft + this.canvasWidth / this.scale;
				const visibleTop = -this.offsetY / this.scale;
				const visibleBottom = visibleTop + this.canvasHeight / this.scale;
				const startX = Math.floor(visibleLeft / this.gridSize) * this.gridSize;
				const endX = Math.ceil(visibleRight / this.gridSize) * this.gridSize;
				const startY = Math.floor(visibleTop / this.gridSize) * this.gridSize;
				const endY = Math.ceil(visibleBottom / this.gridSize) * this.gridSize;

				this.mainCtx.strokeStyle = '#e0e0e0';
				this.mainCtx.lineWidth = 1 / (this.dpr * this.scale);
				for (let x = startX; x <= endX; x += this.gridSize) {
					this.mainCtx.beginPath();
					this.mainCtx.moveTo(x, visibleTop);
					this.mainCtx.lineTo(x, visibleBottom);
					this.mainCtx.stroke();
				}
				for (let y = startY; y <= endY; y += this.gridSize) {
					this.mainCtx.beginPath();
					this.mainCtx.moveTo(visibleLeft, y);
					this.mainCtx.lineTo(visibleRight, y);
					this.mainCtx.stroke();
				}

				// 绘制墙体，单独处理每个线段的样式
				this.sureRoom.forEach(room => {
					if (!room || room.length === 0) return;
					room.forEach((line, index) => {
						if (!line.start || !line.end) return;

						this.mainCtx.beginPath();
						// 墙厚以厘米为单位，转换为网格单位（1网格=10cm）
						const wallThickness = (line.lineHeight / 10) * this.gridSize; // 墙厚（网格单位）
						this.mainCtx.strokeStyle = line === this.selectedLine ? '#ff0000' : this
							.getWallStyle(line.wallType || 1);
						this.mainCtx.lineJoin = 'miter';
						this.mainCtx.lineCap = 'square';

						if (line.wallType === 3) {
							// 玻璃墙：处理直线和弧线
							const startScreen = worldToScreen.call(this, line.start);
							const endScreen = worldToScreen.call(this, line.end);
							const halfWidth = wallThickness / 2;

							if (line.type === 'arc' && line.controlPoint) {
								// 弧线玻璃墙：绘制弧形带+斜线填充+边框
								const controlScreen = worldToScreen.call(this, line.controlPoint);

								// 计算法向量以偏移弧线，形成弧形带
								const dx1 = controlScreen.x - startScreen.x;
								const dy1 = controlScreen.y - startScreen.y;
								const dx2 = endScreen.x - controlScreen.x;
								const dy2 = endScreen.y - controlScreen.y;
								const len1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
								const len2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
								const nx1 = len1 ? -dy1 / len1 : 0;
								const ny1 = len1 ? dx1 / len1 : 0;
								const nx2 = len2 ? -dy2 / len2 : 0;
								const ny2 = len2 ? dx2 / len2 : 0;

								// 计算内外弧线的控制点和端点
								const outerStart = {
									x: startScreen.x + nx1 * halfWidth,
									y: startScreen.y + ny1 * halfWidth
								};
								const innerStart = {
									x: startScreen.x - nx1 * halfWidth,
									y: startScreen.y - ny1 * halfWidth
								};
								const outerEnd = {
									x: endScreen.x + nx2 * halfWidth,
									y: endScreen.y + ny2 * halfWidth
								};
								const innerEnd = {
									x: endScreen.x - nx2 * halfWidth,
									y: endScreen.y - ny2 * halfWidth
								};
								const outerControl = {
									x: controlScreen.x + (nx1 + nx2) * halfWidth / 2,
									y: controlScreen.y + (ny1 + ny2) * halfWidth / 2
								};
								const innerControl = {
									x: controlScreen.x - (nx1 + nx2) * halfWidth / 2,
									y: controlScreen.y - (ny1 + ny2) * halfWidth / 2
								};

								// 绘制弧形带（用于裁剪）
								this.mainCtx.save();
								this.mainCtx.beginPath();
								this.mainCtx.moveTo(outerStart.x, outerStart.y);
								this.mainCtx.quadraticCurveTo(outerControl.x, outerControl.y, outerEnd.x,
									outerEnd.y);
								this.mainCtx.lineTo(innerEnd.x, innerEnd.y);
								this.mainCtx.quadraticCurveTo(innerControl.x, innerControl.y, innerStart.x,
									innerStart.y);
								this.mainCtx.closePath();
								this.mainCtx.clip(); // 限制斜线在弧形带内

								// 绘制斜线填充
								this.mainCtx.strokeStyle = this.getWallStyle(3);
								this.mainCtx.lineWidth = 1 / (this.dpr * this.scale);
								const hatchSpacing = 5 / this.scale; // 斜线间距
								const hatchAngle = Math.PI / 4; // 45度斜线
								const minX = Math.min(outerStart.x, outerEnd.x, innerStart.x, innerEnd.x,
									outerControl.x, innerControl.x);
								const maxX = Math.max(outerStart.x, outerEnd.x, innerStart.x, innerEnd.x,
									outerControl.x, innerControl.x);
								const minY = Math.min(outerStart.y, outerEnd.y, innerStart.y, innerEnd.y,
									outerControl.y, innerControl.y);
								const maxY = Math.max(outerStart.y, outerEnd.y, innerStart.y, innerEnd.y,
									outerControl.y, innerControl.y);

								for (let i = minX - (maxY - minY); i <= maxX + (maxY - minY); i +=
									hatchSpacing) {
									this.mainCtx.beginPath();
									this.mainCtx.moveTo(i, minY);
									this.mainCtx.lineTo(i + (maxY - minY), minY + (maxY - minY));
									this.mainCtx.stroke();
								}
								this.mainCtx.restore();

								// 绘制弧形带边框
								this.mainCtx.beginPath();
								this.mainCtx.moveTo(outerStart.x, outerStart.y);
								this.mainCtx.quadraticCurveTo(outerControl.x, outerControl.y, outerEnd.x,
									outerEnd.y);
								this.mainCtx.lineTo(innerEnd.x, innerEnd.y);
								this.mainCtx.quadraticCurveTo(innerControl.x, innerControl.y, innerStart.x,
									innerStart.y);
								this.mainCtx.closePath();
								this.mainCtx.strokeStyle = line === this.selectedLine ? '#ff0000' : this
									.getWallStyle(3);
								this.mainCtx.lineWidth = 2 / (this.dpr * this.scale);
								this.mainCtx.stroke();
							} else {
								// 直线玻璃墙：绘制矩形+斜线填充+边框
								const dx = endScreen.x - startScreen.x;
								const dy = endScreen.y - startScreen.y;
								const angle = Math.atan2(dy, dx);
								const cosA = Math.cos(angle);
								const sinA = Math.sin(angle);
								const perpX = -sinA * halfWidth;
								const perpY = cosA * halfWidth;

								const p1 = {
									x: startScreen.x + perpX,
									y: startScreen.y + perpY
								};
								const p2 = {
									x: startScreen.x - perpX,
									y: startScreen.y - perpY
								};
								const p3 = {
									x: endScreen.x - perpX,
									y: endScreen.y - perpY
								};
								const p4 = {
									x: endScreen.x + perpX,
									y: endScreen.y + perpY
								};
								// 绘制斜线填充
								this.mainCtx.save();
								this.mainCtx.beginPath();
								this.mainCtx.moveTo(p1.x, p1.y);
								this.mainCtx.lineTo(p2.x, p2.y);
								this.mainCtx.lineTo(p3.x, p3.y);
								this.mainCtx.lineTo(p4.x, p4.y);
								this.mainCtx.closePath();
								this.mainCtx.clip(); // 限制斜线在矩形内
								this.mainCtx.strokeStyle = this.getWallStyle(3);
								this.mainCtx.lineWidth = 1 / (this.dpr * this.scale);
								const hatchSpacing = 5 / this.scale; // 斜线间距
								const hatchAngle = Math.PI / 4; // 45度斜线
								const minX = Math.min(p1.x, p2.x, p3.x, p4.x);
								const maxX = Math.max(p1.x, p2.x, p3.x, p4.x);
								const minY = Math.min(p1.y, p2.y, p3.y, p4.y);
								const maxY = Math.max(p1.y, p2.y, p3.y, p4.y);

								for (let i = minX - (maxY - minY); i <= maxX + (maxY - minY); i +=
									hatchSpacing) {
									this.mainCtx.beginPath();
									this.mainCtx.moveTo(i, minY);
									this.mainCtx.lineTo(i + (maxY - minY), minY + (maxY - minY));
									this.mainCtx.stroke();
								}
								this.mainCtx.restore();

								// 绘制矩形边框
								this.mainCtx.beginPath();
								this.mainCtx.moveTo(p1.x, p1.y);
								this.mainCtx.lineTo(p2.x, p2.y);
								this.mainCtx.lineTo(p3.x, p3.y);
								this.mainCtx.lineTo(p4.x, p4.y);
								this.mainCtx.closePath();
								this.mainCtx.strokeStyle = line === this.selectedLine ? '#ff0000' : this
									.getWallStyle(3);
								this.mainCtx.lineWidth = 2 / (this.dpr * this.scale);
								this.mainCtx.stroke();
							}
						} else {
							// 其他墙体类型保持原有逻辑
							this.mainCtx.lineWidth = wallThickness;
							if (line.type === 'arc' && line.controlPoint) {
								this.mainCtx.moveTo(line.start.x, line.start.y);
								this.mainCtx.quadraticCurveTo(line.controlPoint.x, line.controlPoint.y,
									line.end.x, line.end.y);

							} else {
								this.mainCtx.moveTo(line.start.x, line.start.y);
								this.mainCtx.lineTo(line.end.x, line.end.y);
							}
							this.mainCtx.setLineDash([]); // 其他墙体无虚线
							this.mainCtx.stroke();
						}
						// if (line.type === 'arc' && line.controlPoint) {
						//     const bbox = this.getArcBoundingBox(line);
						//     const p1 = worldToScreen.call(this, bbox[0]);
						//     const p2 = worldToScreen.call(this, bbox[1]);
						//     const p3 = worldToScreen.call(this, bbox[2]);
						//     const p4 = worldToScreen.call(this, bbox[3]);

						//     // ✅ 控制台输出世界坐标
						//     console.log('弧线外接矩形顶点（世界坐标）:', bbox);

						//     // ✅ 虚线绘制外接矩形
						//     this.mainCtx.save();
						//     this.mainCtx.strokeStyle = '#ff0000';
						//     this.mainCtx.lineWidth = 1 / (this.dpr * this.scale);
						//     this.mainCtx.setLineDash([5 / this.scale, 5 / this.scale]);
						//     this.mainCtx.beginPath();
						//     this.mainCtx.moveTo(p1.x, p1.y);
						//     this.mainCtx.lineTo(p2.x, p2.y);
						//     this.mainCtx.lineTo(p3.x, p3.y);
						//     this.mainCtx.lineTo(p4.x, p4.y);
						//     this.mainCtx.closePath();
						//     this.mainCtx.stroke();
						//     this.mainCtx.restore();
						// }
					});
				});

				// 计算并绘制封闭图形的面积
				if (this.sureRoom[0] && this.sureRoom[0].length > 2 && !this.linePoints.length) {
					const {
						area
					} = this.calculatePolygonArea(this.sureRoom[0]);
					const worldArea = area;
					const centroid = this.calculateCentroid(this.sureRoom[0]);
					const screenCentroid = worldToScreen.call(this, centroid);

					this.mainCtx.font = `14px Arial`;
					this.mainCtx.fillStyle = 'blue';
					this.mainCtx.textAlign = 'center';
					this.mainCtx.textBaseline = 'middle';
					this.mainCtx.fillText(`${Math.round(worldArea)} cm²`, screenCentroid.x, screenCentroid.y);
				}

				// 绘制门、窗、柱和临时线段
				this.doors.forEach(door => {
					this.drawDoor(door, this.mainCtx);
				});
				this.windows.forEach(window => {
					this.drawWindow(window, this.mainCtx);
				});
				this.pillars.forEach(pillar => {
					this.drawPillar(pillar, this.mainCtx);
				});
				if (this.isDraggingCrosshair && this.tempEndPoint && this.linePoints.length > 0) {
					const start = this.linePoints[this.linePoints.length - 1];
					this.mainCtx.strokeStyle = '#ff6600';
					this.mainCtx.lineWidth = (10 / 10) * this.gridSize;
					this.mainCtx.beginPath();
					this.mainCtx.moveTo(start.x, start.y);
					this.mainCtx.lineTo(this.tempEndPoint.x, this.tempEndPoint.y);
					this.mainCtx.stroke();
				}
				if (this.addDoorPos) this.drawDoor(this.addDoorPos, this.mainCtx);
				if (this.addWindowPos) this.drawWindow(this.addWindowPos, this.mainCtx);
				if (this.addPillarPos) this.drawPillar(this.addPillarPos, this.mainCtx);
				if (this.selectData && this.selectData.type === 'arc' && this.selectData.controlPoint) {
					const controlPoint = worldToScreen.call(this, this.selectData.controlPoint);
					this.mainCtx.fillStyle = 'green';
					this.mainCtx.beginPath();
					this.mainCtx.arc(controlPoint.x, controlPoint.y, 10 / this.scale, 0, Math.PI * 2);
					this.mainCtx.fill();
					this.mainCtx.strokeStyle = 'white';
					this.mainCtx.lineWidth = 2 / (this.dpr * this.scale);
					this.mainCtx.stroke();
				}
				if (this.selectData && this.selectData.class) {
					const controlPoints = this.getControlPoints(this.selectData);
					this.mainCtx.fillStyle = 'blue';
					controlPoints.forEach(point => {
						this.mainCtx.beginPath();
						this.mainCtx.arc(point.x, point.y, 5 / this.scale, 0, Math.PI * 2);
						this.mainCtx.fill();
					});
				}

				if (this.showCrosshair) {
					this.mainCtx.strokeStyle = '#ff4444';
					this.mainCtx.lineWidth = 5 / (this.dpr * this.scale);
					const crosshairSize = 10 / this.scale;
					this.mainCtx.beginPath();
					this.mainCtx.moveTo(this.crosshairX, this.crosshairY - crosshairSize);
					this.mainCtx.lineTo(this.crosshairX, this.crosshairY + crosshairSize);
					this.mainCtx.moveTo(this.crosshairX - crosshairSize, this.crosshairY);
					this.mainCtx.lineTo(this.crosshairX + crosshairSize, this.crosshairY);
					this.mainCtx.stroke();
				}

				this.mainCtx.restore();

				this.mainCtx.save();
				this.sureRoom.forEach(room => {
					room.forEach(line => {
						this.drawSizeLine(line);
					});
				});
				this.mainCtx.restore();
				 // #ifdef APP-PLUS
				  this.mainCtx.draw()
				  // #endif
			},

			// 计算控制点位置
			getControlPoints(item) {
				if (!item || !item.pos) return [];
				const scalePix = this.gridSize / 10; // 1网格=10cm
				let points = [];

				if (item.class === 'door') {
				    const width = (item.width / 10) * this.gridSize;
				    const rot = ((item.rotateDeg || 0) * Math.PI) / 180;
				    const cos = Math.cos(rot), sin = Math.sin(rot);
				    const half = width / 2;
				
				    // 中心点
				    const center = item.pos;
				    // 左右控制点（世界坐标）
				    const left = {
				      x: center.x - half * cos,
				      y: center.y - half * sin
				    };
				    const right = {
				      x: center.x + half * cos,
				      y: center.y + half * sin
				    };
				    points = [left, right];
				  } else if (item.class === 'window') {
					const width = (item.width / 10) * this.gridSize;
					const height = (item.height / 10) * this.gridSize;
					let leftPoint = {
						x: item.pos.x - width / 2,
						y: item.pos.y
					};
					let rightPoint = {
						x: item.pos.x + width / 2,
						y: item.pos.y
					};
					if (item.rotateDeg) {
						const angle = (item.rotateDeg * Math.PI) / 180;
						const cosA = Math.cos(angle);
						const sinA = Math.sin(angle);
						leftPoint = {
							x: item.pos.x + (leftPoint.x - item.pos.x) * cosA - (leftPoint.y - item.pos.y) * sinA,
							y: item.pos.y + (leftPoint.x - item.pos.x) * sinA + (leftPoint.y - item.pos.y) * cosA
						};
						rightPoint = {
							x: item.pos.x + (rightPoint.x - item.pos.x) * cosA - (rightPoint.y - item.pos.y) * sinA,
							y: item.pos.y + (rightPoint.x - item.pos.x) * sinA + (rightPoint.y - item.pos.y) * cosA
						};
					}
					points = [leftPoint, rightPoint];
				} else if (item.class === 'pillar') {
					if (item.type === 1) {
						const width = (item.width / 10) * this.gridSize;
						const height = (item.height / 10) * this.gridSize;
						let leftPoint = {
							x: item.pos.x - width / 2,
							y: item.pos.y
						};
						let rightPoint = {
							x: item.pos.x + width / 2,
							y: item.pos.y
						};
						if (item.rotateDeg) {
							const angle = (item.rotateDeg * Math.PI) / 180;
							const cosA = Math.cos(angle);
							const sinA = Math.sin(angle);
							leftPoint = {
								x: item.pos.x + (leftPoint.x - item.pos.x) * cosA - (leftPoint.y - item.pos.y) * sinA,
								y: item.pos.y + (leftPoint.x - item.pos.x) * sinA + (leftPoint.y - item.pos.y) * cosA
							};
							rightPoint = {
								x: item.pos.x + (rightPoint.x - item.pos.x) * cosA - (rightPoint.y - item.pos.y) *
									sinA,
								y: item.pos.y + (rightPoint.x - item.pos.x) * sinA + (rightPoint.y - item.pos.y) * cosA
							};
						}
						points = [leftPoint, rightPoint];
					} else {
						const radius = (item.width / 10) * this.gridSize / 2;
						points = [{
								x: item.pos.x - radius,
								y: item.pos.y
							},
							{
								x: item.pos.x + radius,
								y: item.pos.y
							}
						];
					}
				}

				return points.map(point => worldToScreen.call(this, point));
			},
			getEventPos(e, canvasRect) {
			  const touch = e.touches[0] || e.changedTouches[0];
			  // 微信小程序
			  if (touch.x !== undefined && touch.y !== undefined) {
			    return {
			      x: touch.x - canvasRect.left,
			      y: touch.y - canvasRect.top
			    };
			  }
			  // App / H5
			  return {
			    x: touch.pageX - canvasRect.left,
			    y: touch.pageY - canvasRect.top
			  };
			},

			handleControlPointStart(e, index) {
			  if (!e.touches || !e.touches[0]) return;
			  this.saveState();
			
			  const { x: canvasX, y: canvasY } = this.getEventPos(e, this.canvasRect);
			  const worldPos = screenToWorld.call(this, { x: canvasX, y: canvasY });
			  const controlPoints = this.getControlPoints(this.selectData);
			
			  const threshold = 20 / this.scale;
			  const point = controlPoints[index];
			  if (distance(worldPos, point) <= threshold) {
			    this.isDraggingControlPoint = true;
			    this.draggingControlPointIndex = index;
			    this.drawAll();
			  }
			},
			
			/* ========== Move ========== */
			/* -------------- 替换开始 -------------- */
			handleControlPointMove(e, index) {
			  if (!this.isDraggingControlPoint || !e.touches[0]) return;
			
			  const { x: canvasX, y: canvasY } = this.getEventPos(e, this.canvasRect);
			  const snapWorld = snapToWallEndpoint.call(this, canvasX, canvasY) || snapToGrid.call(this, canvasX, canvasY);
			
			 /* ========== 左侧控制点拖动 ========== */
			 if (this.draggingControlPointIndex === 0) {
			   const world = snapWorld; // 手指世界坐标
			   const center = this.selectData.pos;
			   const rot = ((this.selectData.rotateDeg || 0) * Math.PI) / 180;
			   const cos = Math.cos(rot), sin = Math.sin(rot);
			 
			   /* 1. 把“右侧端点”从世界 → 局部（以中心为原点）*/
			   const halfOld = (this.selectData.width / 10) * this.gridSize / 2;
			   const rightLocal = halfOld; // 右侧不动
			 
			   /* 2. 手指逆旋转 → 局部 X */
			   const dx = world.x - center.x;
			   const dy = world.y - center.y;
			   const leftLocal = dx * cos + dy * sin;
			 
			   /* 3. 新宽度 & 中心（局部）*/
			   const newWidth = Math.max(rightLocal - leftLocal, 5);
			   const newCenterLocal = (leftLocal + rightLocal) / 2;
			 
			   /* 4. 更新中心（保证右侧世界坐标不变）*/
			   this.selectData.pos.x = center.x + newCenterLocal * cos;
			   this.selectData.pos.y = center.y + newCenterLocal * sin;
			   this.selectData.width = newWidth;
			 
			   /* 5. 同步数组 */
			   const item = this[this.selectData.class + 's'].find(i => i.idx === this.selectData.idx);
			   if (item) {
			     item.width = newWidth;
			     item.pos = { ...this.selectData.pos };
			   }
			 }
			 
			 /* ========== 右侧控制点拖动 ========== */
			 else if (this.draggingControlPointIndex === 1) {
			   const world = snapWorld;
			   const center = this.selectData.pos;
			   const rot = ((this.selectData.rotateDeg || 0) * Math.PI) / 180;
			   const cos = Math.cos(rot), sin = Math.sin(rot);
			 
			   /* 1. 左侧端点局部（不动）*/
			   const leftLocal = -(this.selectData.width / 10) * this.gridSize / 2;
			 
			   /* 2. 手指逆旋转 → 局部 X */
			   const dx = world.x - center.x;
			   const dy = world.y - center.y;
			   const rightLocal = dx * cos + dy * sin;
			 
			   /* 3. 新宽度 & 中心（局部）*/
			   const newWidth = Math.max(rightLocal - leftLocal, 5);
			   const newCenterLocal = (leftLocal + rightLocal) / 2;
			 
			   /* 4. 更新中心（保证左侧世界坐标不变）*/
			   this.selectData.pos.x = center.x + newCenterLocal * cos;
			   this.selectData.pos.y = center.y + newCenterLocal * sin;
			   this.selectData.width = newWidth;
			 
			   /* 5. 同步数组 */
			   const item = this[this.selectData.class + 's'].find(i => i.idx === this.selectData.idx);
			   if (item) {
			     item.width = newWidth;
			     item.pos = { ...this.selectData.pos };
			   }
			 }
			
			  this.drawAll();
			},
			/* -------------- 替换结束 -------------- */
			
			/* ========== End ========== */
			handleControlPointEnd() {
			  this.isDraggingControlPoint = false;
			  this.draggingControlPointIndex = null;
			  this.drawAll();
			},
			// 查找点击的组件
			findClickedItem(canvasX, canvasY) {
				const worldPos = screenToWorld.call(this, {
					x: canvasX,
					y: canvasY
				});
				let closestItem = null;
				let minDistance = Infinity;

				// 检查所有门、窗、柱
				const items = [...this.doors, ...this.windows, ...this.pillars];
				items.forEach(item => {
					const scalePix = 1 / this.scale;
					let boundingBox = null;

					if (item.class === 'door') {
						let width = item.width * scalePix;
						let startPoint = {
							x: item.pos.x - width / 2,
							y: item.pos.y
						};
						let endPoint = {
							x: item.pos.x + width / 2,
							y: item.pos.y
						};

						// 应用旋转角度
						if (item.rotateDeg) {
							const angle = (item.rotateDeg * Math.PI) / 180;
							const cosA = Math.cos(angle);
							const sinA = Math.sin(angle);
							startPoint = {
								x: item.pos.x + (startPoint.x - item.pos.x) * cosA - (startPoint.y - item.pos
									.y) * sinA,
								y: item.pos.y + (startPoint.x - item.pos.x) * sinA + (startPoint.y - item.pos
									.y) * cosA
							};
							endPoint = {
								x: item.pos.x + (endPoint.x - item.pos.x) * cosA - (endPoint.y - item.pos.y) *
									sinA,
								y: item.pos.y + (endPoint.x - item.pos.x) * sinA + (endPoint.y - item.pos.y) *
									cosA
							};
						}

						// 计算门的边界框，扩大范围以提高选中灵敏度
						const threshold = Math.max(15 / this.scale, width / 2);
						const minX = Math.min(startPoint.x, endPoint.x) - threshold;
						const maxX = Math.max(startPoint.x, endPoint.x) + threshold;
						const minY = Math.min(startPoint.y, endPoint.y) - threshold;
						const maxY = Math.max(startPoint.y, endPoint.y) + threshold;

						boundingBox = {
							minX,
							maxX,
							minY,
							maxY
						};

						// 检查点击点是否在边界框内
						if (worldPos.x >= minX && worldPos.x <= maxX && worldPos.y >= minY && worldPos.y <= maxY) {
							const result = closestPointOnLine(worldPos, startPoint, endPoint);
							if (result.distance < minDistance) {
								minDistance = result.distance;
								closestItem = item;
							}
						}
					} else if (item.class === 'window') {
						const width = item.width * scalePix;
						const height = item.height * scalePix;
						let minX = item.pos.x - width / 2;
						let maxX = item.pos.x + width / 2;
						let minY = item.pos.y - height / 2;
						let maxY = item.pos.y + height / 2;

						// 应用旋转角度
						if (item.rotateDeg) {
							const angle = (item.rotateDeg * Math.PI) / 180;
							const cosA = Math.cos(angle);
							const sinA = Math.sin(angle);
							const corners = [{
									x: minX,
									y: minY
								},
								{
									x: maxX,
									y: minY
								},
								{
									x: maxX,
									y: maxY
								},
								{
									x: minX,
									y: maxY
								}
							];
							const rotatedCorners = corners.map(corner => ({
								x: item.pos.x + (corner.x - item.pos.x) * cosA - (corner.y - item.pos
									.y) * sinA,
								y: item.pos.y + (corner.x - item.pos.x) * sinA + (corner.y - item.pos
									.y) * cosA
							}));
							minX = Math.min(...rotatedCorners.map(c => c.x));
							maxX = Math.max(...rotatedCorners.map(c => c.x));
							minY = Math.min(...rotatedCorners.map(c => c.y));
							maxY = Math.max(...rotatedCorners.map(c => c.y));
						}

						// 扩大边界框以提高选中灵敏度
						const threshold = Math.max(15 / this.scale, Math.max(width, height) / 2);
						boundingBox = {
							minX: minX - threshold,
							maxX: maxX + threshold,
							minY: minY - threshold,
							maxY: maxY + threshold
						};

						if (worldPos.x >= minX && worldPos.x <= maxX && worldPos.y >= minY && worldPos.y <= maxY) {
							const dist = distance(worldPos, item.pos);
							if (dist < minDistance) {
								minDistance = dist;
								closestItem = item;
							}
						}
					} else if (item.class === 'pillar') {
						if (item.type === 1) { // 方柱
							const width = item.width * scalePix;
							const height = item.height * scalePix;
							let minX = item.pos.x - width / 2;
							let maxX = item.pos.x + width / 2;
							let minY = item.pos.y - height / 2;
							let maxY = item.pos.y + height / 2;

							// 应用旋转角度，计算实际边界框
							if (item.rotateDeg) {
								const angle = (item.rotateDeg * Math.PI) / 180;
								const cosA = Math.cos(angle);
								const sinA = Math.sin(angle);
								const corners = [{
										x: minX,
										y: minY
									},
									{
										x: maxX,
										y: minY
									},
									{
										x: maxX,
										y: maxY
									},
									{
										x: minX,
										y: maxY
									}
								];
								const rotatedCorners = corners.map(corner => ({
									x: item.pos.x + (corner.x - item.pos.x) * cosA - (corner.y - item
										.pos.y) * sinA,
									y: item.pos.y + (corner.x - item.pos.x) * sinA + (corner.y - item
										.pos.y) * cosA
								}));
								minX = Math.min(...rotatedCorners.map(c => c.x));
								maxX = Math.max(...rotatedCorners.map(c => c.x));
								minY = Math.min(...rotatedCorners.map(c => c.y));
								maxY = Math.max(...rotatedCorners.map(c => c.y));
							}

							// 扩大边界框，确保整个方柱区域可选中
							const threshold = Math.max(15 / this.scale, Math.max(width, height) / 2);
							boundingBox = {
								minX: minX - threshold,
								maxX: maxX + threshold,
								minY: minY - threshold,
								maxY: maxY + threshold
							};

							// 检查点击点是否在边界框内（覆盖整个方柱区域）
							if (worldPos.x >= minX && worldPos.x <= maxX && worldPos.y >= minY && worldPos.y <=
								maxY) {
								minDistance = 0; // 直接选中，优先级最高
								closestItem = item;
							}
						} else { // 圆柱
							const radius = (item.width * scalePix) / 2;
							const dist = distance(worldPos, item.pos);
							const threshold = radius + (15 / this.scale);
							if (dist <= threshold && dist < minDistance) {
								minDistance = dist;
								closestItem = item;
							}
						}
					}
				});

				return closestItem ? {
					item: closestItem
				} : null;
			},
			drawSizeLine(line) {
				if (!line || !line.start || !line.end || isNaN(line.start.x) || isNaN(line.start.y) || isNaN(line.end.x) ||
					isNaN(line.end.y)) {
					return;
				}
				const isCoincident = Math.abs(line.start.x - line.end.x) < 0.0001 && Math.abs(line.start.y - line.end.y) <
					0.0001;
				if (isCoincident) {
					return; // 如果起点和终点重合，跳过绘制
				}
				const start = worldToScreen.call(this, line.start);
				const end = worldToScreen.call(this, line.end);
				if (isNaN(start.x) || isNaN(start.y) || isNaN(end.x) || isNaN(end.y)) {
					return;
				}
				const midWorld = {
					x: (line.start.x + line.end.x) / 2,
					y: (line.start.y + line.end.y) / 2,
				};
				const deltaX = end.x - start.x;
				const deltaY = end.y - start.y;
				const angle = Math.atan2(deltaY, deltaX);
				const perpendicular = {
					x: -deltaY,
					y: deltaX
				};
				const normalize = (vec) => {
					const len = Math.sqrt(vec.x ** 2 + vec.y ** 2);
					return len === 0 ? {
						x: 0,
						y: 0
					} : {
						x: vec.x / len,
						y: vec.y / len
					};
				};
				const normal = normalize(perpendicular);
				const lineThickness = (line.lineHeight / 10) * this.gridSize; // 墙厚以网格单位
				// 偏移量基于网格单位（1网格=10cm），转换为屏幕坐标
				const baseOffset = this.gridSize; // 基础偏移量设为1网格（10cm）
				const lineOffset = Math.max(baseOffset, lineThickness + baseOffset / 2) * this.scale; // 转换为屏幕坐标
				const textOffset = lineOffset + (15 / this.gridSize) * this.gridSize * this.scale; // 文本偏移量随网格比例调整
				// 计算墙的实际长度（厘米），基于世界坐标
				const worldLength = distance(line.start, line.end) * (this.gridSize / 10); // 1网格=10cm
				line.lineWidth = worldLength; // 更新 lineWidth 为厘米单位
				const labelText = `${Math.round(worldLength)} cm`;
				// 计算标注线的屏幕长度，确保与墙体长度对应
				const screenLength = worldLength * (this.gridSize / 10) * this.scale; // 转换为屏幕坐标
				this.mainCtx.strokeStyle = 'red';
				this.mainCtx.lineWidth = 1 / this.dpr;
				this.mainCtx.beginPath();
				const lineStart = {
					x: midWorld.x * this.scale + this.offsetX + normal.x * lineOffset - (screenLength / 2) * Math.cos(
						angle),
					y: midWorld.y * this.scale + this.offsetY + normal.y * lineOffset - (screenLength / 2) * Math.sin(
						angle),
				};
				const lineEnd = {
					x: midWorld.x * this.scale + this.offsetX + normal.x * lineOffset + (screenLength / 2) * Math.cos(
						angle),
					y: midWorld.y * this.scale + this.offsetY + normal.y * lineOffset + (screenLength / 2) * Math.sin(
						angle),
				};
				this.mainCtx.moveTo(lineStart.x, lineStart.y);
				this.mainCtx.lineTo(lineEnd.x, lineEnd.y);
				this.mainCtx.stroke();
				const baseArrowSize = 5; // 基准大小（在 scale=1 时）
				const arrowSize = Math.max(3, Math.min(baseArrowSize * this.scale, 30));
				this.drawArrowhead(this.mainCtx, lineStart.x, lineStart.y, lineEnd.x, lineEnd.y, arrowSize);
				this.drawArrowhead(this.mainCtx, lineEnd.x, lineEnd.y, lineStart.x, lineStart.y, arrowSize);
				const textPos = {
					x: midWorld.x * this.scale + this.offsetX + normal.x * textOffset,
					y: midWorld.y * this.scale + this.offsetY + normal.y * textOffset,
				};
				if (isNaN(textPos.x) || isNaN(textPos.y)) {
					return;
				}
				this.mainCtx.font = `${12 * this.scale}px Arial`; // 字体大小随缩放放大
				this.mainCtx.fillStyle = 'red';
				this.mainCtx.textAlign = 'center';
				this.mainCtx.textBaseline = 'middle';
				this.mainCtx.fillText(labelText, textPos.x, textPos.y);
			},
			calculateAnnotationPositions(line) {
				// 仅用于兼容旧代码，实际绘制逻辑已移至 drawSizeLine
				const startScreen = worldToScreen.call(this, line.start);
				const endScreen = worldToScreen.call(this, line.end);
				return {
					startScreen,
					endScreen
				};
			},
			// 绘制门（修复单开门样式）
			// 绘制门
			drawDoor(data, ctx) {
				 const scalePix = this.gridSize / 10;          // 1 网格 = 10 cm
				  /* ****** 新增：计算中心原点 ****** */
				  let centerWorld;
				  if (data.type === 1) {                        // 单开门
				    const half = (data.width / 10) * this.gridSize/2 ;
				    const rot = ((data.rotateDeg || 0) * Math.PI) / 180;
				    const cos = Math.cos(rot), sin = Math.sin(rot);
				    // 左侧控制点（固定端）
				    const left = {
				      x: data.pos.x - half * cos,
				      y: data.pos.y - half * sin
				    };
				    // 右侧控制点（活动端）
				    const right = {
				      x: data.pos.x + half * cos,
				      y: data.pos.y + half * sin
				    };
				    centerWorld = {                              // 两控制点中心
				      x: (left.x + right.x) / 2,
				      y: (left.y + right.y) / 2
				    };
				  } else {
				    centerWorld = data.pos;                      // 双开门仍用原 pos
				  }
				  /* ****** 新增结束 ****** */
				
				  const screenCenter = worldToScreen.call(this, centerWorld); // 新的屏幕原点
				  ctx.save();
				  if (data.rotateDeg) {
				    ctx.translate(screenCenter.x, screenCenter.y);
				    ctx.rotate((data.rotateDeg * Math.PI) / 180);
				    ctx.translate(-screenCenter.x, -screenCenter.y);
				  }
				
				  const width = (data.width / 10) * this.gridSize; // 厘米→网格→像素
				  ctx.strokeStyle = (this.selectData && this.selectData.idx === data.idx && this.selectData.class === 'door')
				                    ? '#ff0000' : '#333';
				  ctx.lineWidth = 2 / (this.dpr * this.scale);
				
				  if (data.type === 1) {
				    /***** 以 screenCenter 为原点绘制单开门 *****/
				    ctx.beginPath();
				    ctx.moveTo(screenCenter.x - width / 2, screenCenter.y); // 固定端
				    ctx.lineTo(screenCenter.x + width / 2, screenCenter.y); // 活动端
				    ctx.stroke();
				    ctx.beginPath();
				    ctx.arc(screenCenter.x - width / 2, screenCenter.y, width , -Math.PI / 2, 0);
				    ctx.stroke();
				    ctx.beginPath();
				    ctx.moveTo(screenCenter.x - width / 2, screenCenter.y);
				    ctx.lineTo(screenCenter.x - width / 2, screenCenter.y - width );
				    ctx.stroke();
				  }else {
					// 双开门：直线 + 两侧弧线
					ctx.beginPath();
					ctx.moveTo(screenCenter.x - width / 2, screenCenter.y);
					ctx.lineTo(screenCenter.x + width / 2, screenCenter.y);
					ctx.stroke();
					ctx.beginPath();
					ctx.arc(screenCenter.x + width / 2, screenCenter.y, width / 2, Math.PI, -Math.PI / 2);
					ctx.stroke();
					ctx.beginPath();
					ctx.arc(screenCenter.x - width / 2, screenCenter.y, width / 2, -Math.PI / 2, 0);
					ctx.stroke();
					ctx.beginPath();
					ctx.moveTo(screenCenter.x - width / 2, screenCenter.y);
					ctx.lineTo(screenCenter.x - width / 2, screenCenter.y - width / 2);
					ctx.stroke();
					ctx.beginPath();
					ctx.moveTo(screenCenter.x + width / 2, screenCenter.y);
					ctx.lineTo(screenCenter.x + width / 2, screenCenter.y - width / 2);
					ctx.stroke();
				}
				ctx.restore();
			},

			// 绘制窗
			drawWindow(data, ctx) {
				const scalePix = this.gridSize / 10; // 1网格=10cm
				const screenPos = worldToScreen.call(this, data.pos);
				ctx.save();
				if (data.rotateDeg) {
					ctx.translate(screenPos.x, screenPos.y);
					ctx.rotate((data.rotateDeg * Math.PI) / 180);
					ctx.translate(-screenPos.x, -screenPos.y);
				}
				const width = (data.width / 10) * this.gridSize; // 宽度以厘米为单位，转换为网格单位
				const height = (data.height / 10) * this.gridSize; // 高度以厘米为单位，转换为网格单位
				ctx.strokeStyle = this.selectData && this.selectData.idx === data.idx && this.selectData.class ===
					'window' ? '#ff0000' : '#333';
				ctx.lineWidth = 1 / (this.dpr * this.scale);
				ctx.strokeRect(screenPos.x - width / 2, screenPos.y - height / 2, width, height);
				ctx.beginPath();
				ctx.moveTo(screenPos.x - width / 2, screenPos.y - height / 4);
				ctx.lineTo(screenPos.x + width / 2, screenPos.y - height / 4);
				ctx.stroke();
				ctx.beginPath();
				ctx.moveTo(screenPos.x - width / 2, screenPos.y + height / 4);
				ctx.lineTo(screenPos.x + width / 2, screenPos.y + height / 4);
				ctx.stroke();
				ctx.restore();
			},

			// 绘制柱
			drawPillar(data, ctx) {
				const scalePix = this.gridSize / 10; // 1网格=10cm
				const screenPos = worldToScreen.call(this, data.pos);
				ctx.save();
				if (data.rotateDeg) {
					ctx.translate(screenPos.x, screenPos.y);
					ctx.rotate((data.rotateDeg * Math.PI) / 180);
					ctx.translate(-screenPos.x, -screenPos.y);
				}
				ctx.beginPath();
				if (data.type === 2) {
					ctx.arc(screenPos.x, screenPos.y, (data.width / 10) * this.gridSize / 2, 0, Math.PI * 2);
				} else {
					const width = (data.width / 10) * this.gridSize;
					const height = (data.height / 10) * this.gridSize;
					ctx.rect(screenPos.x - width / 2, screenPos.y - height / 2, width, height);
				}
				ctx.fillStyle = this.selectData && this.selectData.idx === data.idx && this.selectData.class === 'pillar' ?
					'#ff6666' : '#ccc';
				ctx.fill();
				ctx.restore();
			},

			// 处理触摸开始事件
			handleTouchStart(e) {
				this.saveState()
				if (e.touches.length === 1) {
					const touch = e.touches[0];
					const canvasX = touch.x - this.canvasRect.left;
					const canvasY = touch.y - this.canvasRect.top;
					this.startX = canvasX;
					this.startY = canvasY;

					// console.log('触摸开始:', {
					// 	canvasX,
					// 	canvasY
					// });

					// 优先检查是否点击控制点
					if (this.selectData && this.selectData.class) {
						const controlPoints = this.getControlPoints(this.selectData);
						const worldPos = screenToWorld.call(this, {
							x: canvasX,
							y: canvasY
						});
						const threshold = 20 / this.scale;
						for (let index = 0; index < controlPoints.length; index++) {
							const point = controlPoints[index];
							const dist = distance(worldPos, point);
							if (dist <= threshold) {
								this.isDraggingControlPoint = true;
								this.draggingControlPointIndex = index;
								// console.log('触发控制点:', index, '距离:', dist, '坐标:', point);
								this.drawAll();
								return;
							}
						}
						// console.log('未点击控制点，检查组件');
					}
					if (this.selectData && this.selectData.type === 'arc' && this.selectData.controlPoint) {
						const worldPos = screenToWorld.call(this, {
							x: canvasX,
							y: canvasY
						});
						const dist = distance(worldPos, this.selectData.controlPoint);
						const threshold = 20 / this.scale;
						if (dist <= threshold) {
							this.isDraggingArcControl = true;
							this.isDraggingControlPoint = true;
							this.draggedControlPoint = 'arcControl';
							this.drawAll();
							return;
						}
					}
					// 检查是否点击组件
					const clickedItem = this.findClickedItem(canvasX, canvasY);
					if (clickedItem) {
						this.selectData = {
							...clickedItem.item,
						};
						this.selectedLine = null;
						this.isDraggingCrosshair = false;
						this.isDrawing = false;
						this.isDraggingItem = true;
						this.draggingItemType = this.selectData.class;
						// console.log('选中组件:', this.selectData.class, 'ID:', this.selectData.idx);
					} else if (this.isNearCrosshair(canvasX, canvasY)) {
						this.isDraggingCrosshair = true;
						this.isDrawing = true;
						this.selectedLine = null;
						this.selectData = null;
						this.modMainData = null; // 关闭编辑弹窗
						this.linePoints.push({
							x: this.crosshairX,
							y: this.crosshairY
						});
						this.tempEndPoint = null;
					} else {
						const clickedLine = this.findClickedLine(canvasX, canvasY);
						if (clickedLine) {
							this.selectedLine = clickedLine.line;
							this.selectData = {
								...clickedLine.line
							};
							this.isDraggingCrosshair = false;
							this.isDrawing = false;
						} else {
							this.selectedLine = null;
							this.selectData = null;
							this.modMainData = null; // 关闭编辑弹窗
							this.isDragging = true;
							this.isDraggingCrosshair = false;
							this.isDrawing = false;
							this.isDraggingItem = false;
						}
					}
					this.initialPinchDistance = null;
				} else if (e.touches.length === 2) {
					this.isDragging = false;
					this.isDraggingCrosshair = false;
					this.isDrawing = false;
					this.isDraggingItem = false;
					this.selectedLine = null;
					this.selectData = null;
					this.modMainData = null; // 关闭编辑弹窗
					const touch1 = e.touches[0];
					const touch2 = e.touches[1];
					const canvasX1 = touch1.x - this.canvasRect.left;
					const canvasY1 = touch1.y - this.canvasRect.top;
					const canvasX2 = touch2.x - this.canvasRect.left;
					const canvasY2 = touch2.y - this.canvasRect.top;
					this.initialPinchDistance = this.getPinchDistance({
						x: canvasX1,
						y: canvasY1
					}, {
						x: canvasX2,
						y: canvasY2
					});
					const center = this.getPinchCenter({
						x: canvasX1,
						y: canvasY1
					}, {
						x: canvasX2,
						y: canvasY2
					});
					this.pinchCenter.x = center.x;
					this.pinchCenter.y = center.y;
				}
				this.drawAll();
			},


			handleTouchMove(e) {
				if (e.touches.length === 2) {
					const touch1 = e.touches[0];
					const touch2 = e.touches[1];
					const canvasX1 = touch1.x - this.canvasRect.left;
					const canvasY1 = touch1.y - this.canvasRect.top;
					const canvasX2 = touch2.x - this.canvasRect.left;
					const canvasY2 = touch2.y - this.canvasRect.top;
					const currentDistance = this.getPinchDistance({
						x: canvasX1,
						y: canvasY1
					}, {
						x: canvasX2,
						y: canvasY2
					});
					if (this.initialPinchDistance) {
						const scaleChange = currentDistance / this.initialPinchDistance;
						let newScale = this.scale * scaleChange;
						newScale = Math.max(this.minScale, Math.min(this.maxScale, newScale));

						// 以十字星标为中心进行缩放
						const crosshairScreenX = this.crosshairX * this.scale + this.offsetX;
						const crosshairScreenY = this.crosshairY * this.scale + this.offsetY;
						const scaleRatio = newScale / this.scale;

						// 更新偏移量以保持十字星标位置不变
						this.offsetX = crosshairScreenX - this.crosshairX * newScale;
						this.offsetY = crosshairScreenY - this.crosshairY * newScale;

						this.scale = newScale;
						this.initialPinchDistance = currentDistance;
						this.pinchCenter.x = crosshairScreenX;
						this.pinchCenter.y = crosshairScreenY;
						this.drawAll();
					}
				} else {
					// 保留原单指触摸逻辑
					const touch = e.touches[0];
					const canvasX = touch.x - this.canvasRect.left;
					const canvasY = touch.y - this.canvasRect.top;
					if (this.isDraggingArcControl && this.draggedControlPoint === 'arcControl') {
						const worldPos = screenToWorld.call(this, {
							x: canvasX,
							y: canvasY
						});
						const snappedPos = snapToGrid.call(this, canvasX, canvasY);
						if (this.selectData && this.selectData.type === 'arc') {
							this.selectData.controlPoint = snappedPos;
							this.selectedLine.controlPoint = snappedPos;
							this.sureRoom.forEach(room => {
								const line = room.find(l => l.idx === this.selectedLine.idx);
								if (line) {
									line.controlPoint = snappedPos;
								}
							});
							this.drawAll();
						}
						return;
					}
					if (this.isDraggingControlPoint && this.draggingControlPointIndex !== null) {
						this.handleControlPointMove(e, this.draggingControlPointIndex);
					} else if (this.isDraggingItem && this.selectData && this.draggingItemType === this.selectData.class) {
						const snappedPos = snapToGrid.call(this, canvasX, canvasY);
						this.selectData.pos = snappedPos;
						const targetArray = this[this.selectData.class + 's'];
						const item = targetArray.find(i => i.idx === this.selectData.idx);
						if (item) {
							item.pos = snappedPos;
							// console.log('Dragging item:', this.selectData.class, 'ID:', this.selectData.idx, 'to pos:',
							// snappedPos);
						} else {
							// console.warn('未找到对应组件:', this.selectData.class, 'ID:', this.selectData.idx);
						}
						this.drawAll();
					} else if (this.isDraggingCrosshair) {
						const snapped = snapToWallEndpoint.call(this, canvasX, canvasY) || snapToGrid.call(this, canvasX,
							canvasY);
						this.crosshairX = snapped.x;
						this.crosshairY = snapped.y;
						this.tempEndPoint = snapped;
						this.drawAll();
					} else if (this.isDragging) {
						const deltaX = canvasX - this.startX;
						const deltaY = canvasY - this.startY;
						this.offsetX += deltaX / this.scale;
						this.offsetY += deltaY / this.scale;
						const maxOffsetX = this.canvasWidth * 2;
						const maxOffsetY = this.canvasHeight * 2;
						this.offsetX = Math.max(-maxOffsetX, Math.min(maxOffsetX, this.offsetX));
						this.offsetY = Math.max(-maxOffsetY, Math.min(maxOffsetY, this.offsetY));
						this.startX = canvasX;
						this.startY = canvasY;
						this.drawAll();
					}
				}
			},
			handleTouchEnd(e) {
				if (this.isDraggingArcControl) {
					this.isDraggingArcControl = false;
					this.isDraggingControlPoint = false;
					this.draggedControlPoint = null;
					this.drawAll();
				}
				if (this.isDraggingControlPoint) {
					this.handleControlPointEnd();
				}
				if (this.isDraggingItem) {
					this.isDraggingItem = false;
					this.draggingItemType = null;
					// console.log('End dragging item:', this.selectData.class, 'ID:', this.selectData.idx);
				}
				if (this.isDraggingCrosshair && e.changedTouches.length > 0) {
					const touch = e.changedTouches[0] || e.mp?.changedTouches?.[0]; // 微信老基础库
					const pageX = touch?.pageX ?? touch?.x ?? 0;   // App 端用 x/y
					const pageY = touch?.pageY ?? touch?.y ?? 0;
					const canvasX = pageX - this.canvasRect.left;
					const canvasY = pageY - this.canvasRect.top;
					console.log(canvasX,canvasY)
					if (!isNaN(canvasX) && !isNaN(canvasY)) {
						const snapped = snapToWallEndpoint.call(this, canvasX, canvasY) || snapToGrid.call(this, canvasX,
							canvasY);
						this.crosshairX = snapped.x;
						this.crosshairY = snapped.y;
						if (this.tempEndPoint) {
							this.linePoints.push(snapped);
							if (this.linePoints.length >= 2) {
								this.sureRoom[0] = this.sureRoom[0] || [];
								const newLine = {
									start: this.linePoints[this.linePoints.length - 2],
									end: this.linePoints[this.linePoints.length - 1],
									type: 'line',
									lineHeight: 10, // 默认墙厚10cm
									lineWidth: distance(
										this.linePoints[this.linePoints.length - 2],
										this.linePoints[this.linePoints.length - 1]
									) * this.gridSize, // 厘米
									idx: this.sureRoom[0].length + 1,
									wallType: this.modMainData?.wallType || 1
								};
								this.sureRoom[0].push(newLine);
								console.log('正式墙已写入', JSON.stringify(newLine));
								this.waitCloseLine = true;
								if (this.isNearStartingPoint(snapped)) {
									this.closePic();
								}
							}
						}
					}
				}
				this.isDragging = false;
				this.isDraggingCrosshair = false;
				this.isDrawing = false;
				this.tempEndPoint = null;
				this.initialPinchDistance = null;
				this.drawAll();
				setTimeout(() => this.drawAll(), 50);
			},
			isNearStartingPoint(point) {
				if (!this.linePoints[0]) return false;
				const threshold = this.gridSize / this.scale;
				const dist = distance(point, this.linePoints[0]);
				// console.log('Distance to starting point:', dist, 'Threshold:', threshold);
				return dist < threshold;
			},
			findClickedLine(canvasX, canvasY) {
				const worldPos = screenToWorld.call(this, {
					x: canvasX,
					y: canvasY
				});
				let closest = null;
				let minDistance = Infinity;
				const baseThreshold = 15 / this.scale; // 基础点击阈值
				this.sureRoom.flat().forEach(line => {
					// 根据墙体厚度动态调整阈值
					const lineThickness = (line.lineHeight / 10) * this.gridSize / this.scale; // 转换为屏幕坐标的厚度
					const threshold = Math.max(baseThreshold, lineThickness); // 使用较大值作为点击阈值
					if (line.type === 'arc' && line.controlPoint) {
						const segments = 10;
						let prevPoint = line.start;
						for (let i = 1; i <= segments; i++) {
							const t = i / segments;
							const currentPoint = {
								x: (1 - t) * (1 - t) * line.start.x + 2 * (1 - t) * t * line.controlPoint.x +
									t * t * line.end.x,
								y: (1 - t) * (1 - t) * line.start.y + 2 * (1 - t) * t * line.controlPoint.y +
									t * t * line.end.y,
							};
							const result = closestPointOnLine(worldPos, prevPoint, currentPoint);
							if (result.distance < minDistance && result.distance <= threshold) {
								minDistance = result.distance;
								closest = {
									line,
									point: result.point
								};
							}
							prevPoint = currentPoint;
						}
					} else {
						const result = closestPointOnLine(worldPos, line.start, line.end);
						if (result.distance < minDistance && result.distance <= threshold) {
							minDistance = result.distance;
							closest = {
								line,
								point: result.point
							};
						}
					}
				});
				return closest;
			},
			toggleEditLineMode() {
				this.isEditingLine = !this.isEditingLine;
				if (!this.isEditingLine) {
					this.selectedLine = null;
					this.selectData = null;
					this.editingEndpoint = null;
				}
				this.drawAll();
			},
			getPinchDistance(touch1, touch2) {
				const dx = touch2.x - touch1.x;
				const dy = touch2.y - touch1.y;
				return Math.sqrt(dx * dx + dy * dy);
			},
			getPinchCenter(touch1, touch2) {
				return {
					x: (touch1.x + touch2.x) / 2,
					y: (touch1.y + touch2.y) / 2
				};
			},
			isNearCrosshair(x, y) {
				const screenX = this.crosshairX * this.scale + this.offsetX;
				const screenY = this.crosshairY * this.scale + this.offsetY;
				const threshold = Math.min(
					Math.max(30 / this.scale, 20),
					50 // ✅ 最大阈值不超过 50px
				);
				return Math.abs(x - screenX) < threshold && Math.abs(y - screenY) < threshold;
			},
			handleAddItemStart(e, addItemType, data) {
				if (!e.touches || !e.touches[0]) return;
				const touch = e.touches[0];
				const canvasX = touch.pageX - this.canvasRect.left;
				const canvasY = touch.pageY - this.canvasRect.top;

				// 转换为世界坐标
				const worldPos = screenToWorld.call(this, {
					x: canvasX,
					y: canvasY
				});

				// 创建临时组件用于拖动预览
				const tempItem = {
					...data,
					pos: worldPos, // 初始位置
					class: addItemType,
					idx: -1, // 临时标识
				};
				this.saveState()
				this[`add${addItemType.charAt(0).toUpperCase() + addItemType.slice(1)}Pos`] = tempItem;
				this.draggingItemType = addItemType; // 记录当前拖动类型
				this.isDraggingItem = true; // 启用拖动标志

				// console.log(`Start dragging ${addItemType} at:`, worldPos);
				this.drawAll();
			},

			handleAddItemMove(e, addItemType, data) {
				if (!this.isDraggingItem || !e.touches[0] || this.draggingItemType !== addItemType) return;
				const touch = e.touches[0];
				const canvasX = touch.pageX - this.canvasRect.left;
				const canvasY = touch.pageY - this.canvasRect.top;

				// 更新位置（吸附到墙体或网格）
				const snappedPos = snapToWallEndpoint.call(this, canvasX, canvasY) || snapToGrid.call(this, canvasX,
					canvasY);

				// 更新临时预览位置
				this[`add${addItemType.charAt(0).toUpperCase() + addItemType.slice(1)}Pos`].pos = snappedPos;

				// console.log(`Moving ${addItemType} to:`, snappedPos);
				this.drawAll();
			},

			handleAddItemEnd(e, addItemType, data) {
				if (!this.isDraggingItem || !e.changedTouches[0] || this.draggingItemType !== addItemType) return;
				const touch = e.changedTouches[0];
				const canvasX = touch.pageX - this.canvasRect.left;
				const canvasY = touch.pageY - this.canvasRect.top;

				// 最终位置
				const snappedPos = snapToWallEndpoint.call(this, canvasX, canvasY) || snapToGrid.call(this, canvasX,
					canvasY);

				// 创建并添加最终组件
				const tempItem = this[`add${addItemType.charAt(0).toUpperCase() + addItemType.slice(1)}Pos`];
				const newItem = {
					...tempItem,
					pos: snappedPos,
					idx: this[addItemType + 's'].length,
				};
				this[addItemType + 's'].push(newItem);

				// 清理
				this[`add${addItemType.charAt(0).toUpperCase() + addItemType.slice(1)}Pos`] = null;
				this.isDraggingItem = false;
				this.draggingItemType = null;

				// console.log(`Added ${addItemType} at final pos:`, snappedPos);
				this.drawAll();
			},

			touchStartAll(e) {},
			touchMoveAll(e) {
				if (!this.addData) return;
				const touchPos = screenToWorld.call(this, {
					x: e.touches[0].pageX - this.canvasRect.left,
					y: e.touches[0].pageY - this.canvasRect.top,
				});
				const closestWall = this.findClosestWall(touchPos);
				const snapPos = closestWall ? closestWall.point : snapToGrid.call(this, touchPos.x, touchPos.y);
				if (this.addData.classType === 'door') {
					this.addDoorPos = {
						...this.addData.data,
						pos: snapPos,
						idx: this.doors.length,
						class: 'door',
					};
					if (closestWall) {
						const wallStart = worldToScreen.call(this, closestWall.wall.start);
						const wallEnd = worldToScreen.call(this, closestWall.wall.end);
						const wallAngle = Math.atan2(wallEnd.y - wallStart.y, wallEnd.x - wallStart.x);
						this.addDoorPos.rotateDeg = parseInt(wallAngle * (180 / Math.PI));
						if (this.addDoorPos.rotateDeg < 0) this.addDoorPos.rotateDeg += 360;
						this.addDoorPos.wall = closestWall.wall;
					}
				} else if (this.addData.classType === 'window') {
					this.addWindowPos = {
						...this.addData.data,
						pos: snapPos,
						idx: this.windows.length,
						class: 'window',
						height: closestWall ? closestWall.wall.lineHeight : this.addData.data.height,
					};
					if (closestWall) {
						const wallStart = worldToScreen.call(this, closestWall.wall.start);
						const wallEnd = worldToScreen.call(this, closestWall.wall.end);
						const wallAngle = Math.atan2(wallEnd.y - wallStart.y, wallEnd.x - wallStart.x);
						this.addWindowPos.rotateDeg = parseInt(wallAngle * (180 / Math.PI));
						if (this.addWindowPos.rotateDeg < 0) this.addWindowPos.rotateDeg += 360;
					}
				} else if (this.addData.classType === 'pillar') {
					this.addPillarPos = {
						...this.addData.data,
						pos: snapPos,
						idx: this.pillars.length,
						class: 'pillar',
					};
					if (closestWall) {
						const wallStart = worldToScreen.call(this, closestWall.wall.start);
						const wallEnd = worldToScreen.call(this, closestWall.wall.end);
						const wallAngle = Math.atan2(wallEnd.y - wallStart.y, wallEnd.x - wallStart.x);
						this.addPillarPos.rotateDeg = parseInt(wallAngle * (180 / Math.PI));
						if (this.addPillarPos.rotateDeg < 0) this.addPillarPos.rotateDeg += 360;
					}
				}
				this.drawAll();
			},

			touchEndAll(e) {
				if (!this.addData) return;
				if (this.addData.classType === 'door') {
					this.doors.push(this.addDoorPos);
					this.addDoorPos = null;
				} else if (this.addData.classType === 'window') {
					this.windows.push(this.addWindowPos);
					this.addWindowPos = null;
				} else if (this.addData.classType === 'pillar') {
					this.pillars.push(this.addPillarPos);
					this.addPillarPos = null;
				}
				this.addData = null;
				this.drawAll();
			},
			convertToArc() {
				if (!this.selectData || this.selectData.type !== 'line') return;
				this.saveState()
				const midPoint = {
					x: (this.selectData.start.x + this.selectData.end.x) / 2,
					y: (this.selectData.start.y + this.selectData.end.y) / 2,
				};
				const dx = this.selectData.end.x - this.selectData.start.x;
				const dy = this.selectData.end.y - this.selectData.start.y;
				const perp = {
					x: -dy,
					y: dx
				};
				const len = Math.sqrt(perp.x * perp.x + perp.y * perp.y);
				const scale = distance(this.selectData.start, this.selectData.end) * 0.3;
				const offset = {
					x: (perp.x / len) * scale,
					y: (perp.y / len) * scale
				};
				this.selectData.type = 'arc';
				this.selectData.controlPoint = {
					x: midPoint.x + offset.x,
					y: midPoint.y + offset.y
				};
				this.selectedLine.type = 'arc';
				this.selectedLine.controlPoint = {
					x: midPoint.x + offset.x,
					y: midPoint.y + offset.y
				};
				this.drawAll();
			},
			convertToLine() {
				if (!this.selectData || this.selectData.type !== 'arc') return;
				this.saveState()
				this.selectData.type = 'line';
				this.selectData.controlPoint = null;
				this.selectedLine.type = 'line';
				this.selectedLine.controlPoint = null;
				this.drawAll();
			},
			addNum(num) {
				this.inputNum = (this.inputNum || '') + num;
			},
			delNum() {
				this.inputNum = this.inputNum ? this.inputNum.slice(0, -1) : null;
			},
			sureNum() {
				if (!this.inputNum || !this.modMainData) return;
				this.saveState()
				const newValue = parseFloat(this.inputNum); // 新墙长，单位：厘米
				if (this.statusSelect === 1) {
					// 更新墙厚（保持不变）
					this.modMainData.lineHeight = newValue;
					this.selectData.lineHeight = newValue;
					if (this.selectedLine) {
						this.selectedLine.lineHeight = newValue;
						this.sureRoom.forEach(room => {
							const line = room.find(l => l.idx === this.selectedLine.idx);
							if (line) line.lineHeight = newValue;
						});
					}
				} else if (this.statusSelect === 2) {
					// 更新墙长
					this.modMainData.lineWidth = newValue;
					this.selectData.lineWidth = newValue;
					if (this.selectedLine) {
						this.selectedLine.lineWidth = newValue;

						// 计算墙的当前方向和长度
						const dx = this.selectedLine.end.x - this.selectedLine.start.x;
						const dy = this.selectedLine.end.y - this.selectedLine.start.y;
						const currentLength = Math.sqrt(dx * dx + dy * dy); // 当前长度（网格单位）
						const targetLength = newValue / (this.gridSize / 10); // 新长度（网格单位，1网格=10cm）

						// 如果当前长度不为0，调整 end 点
						if (currentLength > 0) {
							const scale = targetLength / currentLength;
							this.selectedLine.end.x = this.selectedLine.start.x + dx * scale;
							this.selectedLine.end.y = this.selectedLine.start.y + dy * scale;

							// 更新 sureRoom 中对应线段的 end 坐标
							this.sureRoom.forEach(room => {
								const line = room.find(l => l.idx === this.selectedLine.idx);
								if (line) {
									line.lineWidth = newValue;
									line.end.x = this.selectedLine.end.x;
									line.end.y = this.selectedLine.end.y;
								}
							});
						}
					}
				}
				this.inputNum = null;
				this.modMainData = null;
				const lastRoom = this.sureRoom[0];
				if (lastRoom && lastRoom.length > 0) {
					const lastLine = lastRoom[lastRoom.length - 1];
					if (lastLine.idx === this.selectedLine.idx) {
						this.crosshairX = lastLine.end.x;
						this.crosshairY = lastLine.end.y;
					}
				}
				this.drawAll();
				// console.log('Wall properties updated, sureRoom:', this.sureRoom);
				uni.showToast({
					title: '属性已更新',
					icon: 'success'
				});
			},
			changeWall(type) {
				if (!this.modMainData || !this.selectedLine) return;
				this.saveState()
				this.modMainData.wallType = type;
				this.selectData.wallType = type;
				this.selectedLine.wallType = type;
				this.sureRoom.forEach(room => {
					const line = room.find(l => l.idx === this.selectedLine.idx);
					if (line) {
						line.wallType = type; // Only update the specific line
					}
				});
				this.drawAll();
			},
			getWallStyle(wallType) {
				// 根据墙体类型返回不同的样式
				switch (wallType) {
					case 1: // 砌体墙
						return '#333333'; // 深灰色
					case 2: // 剪力墙
						return '#0066cc'; // 蓝色
					case 3: // 玻璃墙
						return '#000'; // 青色
					default:
						return '#333333'; // 默认砌体墙
				}
			},
			modData() {
				this.modMainData = {
					...this.selectData
				};
				this.drawAll()
			},
			rotateItem() {
				if (!this.selectData || this.selectData.type === 'line' || this.selectData.type === 'arc') return;
				this.saveState()
				// 更新 selectData 的旋转角度
				this.selectData.rotateDeg = (this.selectData.rotateDeg || 0) + 90;
				if (this.selectData.rotateDeg >= 360) this.selectData.rotateDeg -= 360;

				// 同步到对应数组
				const targetArray = this[this.selectData.class + 's'];
				const item = targetArray.find(i => i.idx === this.selectData.idx);
				if (item) {
					item.rotateDeg = this.selectData.rotateDeg;
					// console.log('旋转组件:', this.selectData.class, 'ID:', this.selectData.idx, '角度:', this.selectData
					// 	.rotateDeg);
				} else {
					console.warn('未找到对应组件:', this.selectData.class, 'ID:', this.selectData.idx);
				}
				this.drawAll();
			},

			resetPoint() {
				this.saveState();
				// 重置十字星标到画布中心
				const centerX = this.canvasWidth / 2 / this.scale;
				const centerY = this.canvasHeight / 2 / this.scale;
				this.crosshairX = snapToGrid.call(this, centerX, centerY).x;
				this.crosshairY = snapToGrid.call(this, centerX, centerY).y;
				this.crossesIn = false; // 进入拖动模式
				this.showCrosshair = false; // 隐藏十字星标
				this.resetSelf = true;
				this.linePoints = []; // 清空当前线段点
				this.waitCloseLine = false; // 重置闭合状态
				// console.log('Reset crosshair to:', {
				// 	x: this.crosshairX,
				// 	y: this.crosshairY
				// }, 'crossesIn:', this.crossesIn, 'showCrosshair:', this.showCrosshair);
				this.drawAll();
			},
			handleSetCrossStart(e) {
				const touch = e.touches[0];
				const canvasX = touch.pageX - this.canvasRect.left;
				const canvasY = touch.pageY - this.canvasRect.top;
				this.startX = canvasX;
				this.startY = canvasY;
				this.isDraggingCrosshair = true;
				this.crossesIn = false;
				this.showCrosshair = false; // 保持隐藏直到拖动
				// console.log('Start dragging crosshair, startX:', canvasX, 'startY:', canvasY, 'canvasRect:', this
				// 	.canvasRect);
				this.drawAll();
			},
			handleSetCrossMove(e) {
				if (this.isDraggingCrosshair && e.touches.length > 0) {
					const touch = e.touches[0];
					const canvasX = touch.pageX - this.canvasRect.left;
					const canvasY = touch.pageY - this.canvasRect.top;
					if (!isNaN(canvasX) && !isNaN(canvasY)) {
						const snapped = snapToGrid.call(this, canvasX, canvasY);
						this.crosshairX = snapped.x;
						this.crosshairY = snapped.y;
						this.showCrosshair = true; // 拖动时显示十字星标
						// console.log('Moving crosshair to:', {
						// 	x: this.crosshairX,
						// 	y: this.crosshairY
						// }, 'canvasX:', canvasX, 'canvasY:', canvasY, 'showCrosshair:', this.showCrosshair);
						this.drawAll();
					}
				}
			},
			handleSetCrossEnd(e) {
				if (this.isDraggingCrosshair && e.changedTouches.length > 0) {
					const touch = e.changedTouches[0];
					const canvasX = touch.pageX - this.canvasRect.left;
					const canvasY = touch.pageY - this.canvasRect.top;
					this.saveState();
					if (!isNaN(canvasX) && !isNaN(canvasY)) {
						const snapped = snapToWallEndpoint.call(this, canvasX, canvasY) || snapToGrid.call(this, canvasX,
							canvasY);
						this.crosshairX = snapped.x;
						this.crosshairY = snapped.y;
						this.crossesIn = true; // 结束拖动，恢复初始状态
						this.isDraggingCrosshair = false;
						this.showCrosshair = true; // 确保十字星标显示
						// console.log('End dragging crosshair, final position:', {
						// 	x: this.crosshairX,
						// 	y: this.crosshairY
						// }, 'canvasX:', canvasX, 'canvasY:', canvasY, 'snapped:', snapped);
						this.drawAll();
					}
				}
			},
			closePic() {
				if (this.linePoints.length >= 2) {
					// this.sureRoom[0] = this.sureRoom[0] || [];
					// const newLine = {
					// 	start: this.linePoints[this.linePoints.length - 1],
					// 	end: this.linePoints[0],
					// 	type: 'line',
					// 	lineHeight: 10,
					// 	lineWidth: distance(this.linePoints[this.linePoints.length - 1], this.linePoints[0]) * this
					// 		.gridSize * 10,
					// 	idx: this.sureRoom[0].length + 1,
					// };
					// // if(this.linePoints[0].start==this.linePoints[this.linePoints.length-1].start&&this.linePoints[0].end==this.linePoints[this.linePoints.length-1].end){

					// // }
					// this.sureRoom[0].push(newLine);
					this.linePoints = [];
					this.waitCloseLine = false;
					this.showCrosshair = false;


					// this.drawAll();
					uni.showToast({
						title: '房间已闭合',
						icon: 'success'
					});
				} else {
					uni.showToast({
						title: '至少需要两个点才能闭合',
						icon: 'none'
					});
				}
			},
			addItems() {
				this.addItemsShow = true;
			},
			findClosestWall(point) {
				let threshold = 10 / this.scale;
				let closest = null;
				let minDistance = Infinity;
				let closestPoint = null;
				const allWalls = [...this.sureRoom.flat()];
				allWalls.forEach(wall => {
					if (wall.type === 'arc' && wall.controlPoint) {
						const segments = 10;
						let prevPoint = wall.start;
						for (let i = 1; i <= segments; i++) {
							const t = i / segments;
							const currentPoint = {
								x: (1 - t) * (1 - t) * wall.start.x + 2 * (1 - t) * t * wall.controlPoint.x +
									t * t * wall.end.x,
								y: (1 - t) * (1 - t) * wall.start.y + 2 * (1 - t) * t * wall.controlPoint.y +
									t * t * wall.end.y,
							};
							const result = closestPointOnLine(point, prevPoint, currentPoint);
							if (result.distance < minDistance) {
								minDistance = result.distance;
								closest = wall;
								closestPoint = result.point;
							}
							prevPoint = currentPoint;
						}
					} else {
						const result = closestPointOnLine(point, wall.start, wall.end);
						if (result.distance < minDistance) {
							minDistance = result.distance;
							closest = wall;
							closestPoint = result.point;
						}
					}
				});
				return minDistance <= threshold ? {
					wall: closest,
					point: closestPoint
				} : null;
			},
			calculatePolygonArea(lines) {
			  let area = 0;
			  const points = [];
			
			  for (let i = 0; i < lines.length; i++) {
			    const line = lines[i];
			    if (line.type === 'arc' && line.controlPoint) {
			      const arcPoints = this.discretizeArc(line.start, line.end, line.controlPoint);
			      arcPoints.forEach(p => points.push(p));
			    } else {
			      points.push(line.start);
			    }
			  }
			
			  // 闭合路径
			  const n = points.length;
			  for (let i = 0; i < n; i++) {
			    const j = (i + 1) % n;
			    area += points[i].x * points[j].y;
			    area -= points[j].x * points[i].y;
			  }
			
			  area = Math.abs(area) / 2;
			  return { area };
			},
			 discretizeArc(start, end, controlPoint, segments = 20) {
			  const points = [start];
			  for (let i = 1; i <= segments; i++) {
			    const t = i / segments;
			    const x = (1 - t) * (1 - t) * start.x + 2 * (1 - t) * t * controlPoint.x + t * t * end.x;
			    const y = (1 - t) * (1 - t) * start.y + 2 * (1 - t) * t * controlPoint.y + t * t * end.y;
			    points.push({ x, y });
			  }
			  return points;
			},
			// 重新组织页面数据
			reorganizeData() {
				let that = this
				if (!this.defaultData || !this.defaultData.drawCadInfos) return;

				this.sureRoom = [
					[]
				];
				this.doors = [];
				this.windows = [];
				this.pillars = [];

				this.defaultData.drawCadInfos.forEach(group => {
					group.drawCadDetails.forEach(item => {
						const drawData = JSON.parse(item.drawStr || '{}');
						if (group.drawType === 1) {
							// 墙体
							this.sureRoom[0].push({
								...drawData,
								wallType: drawData.wallType || 1,
								lineHeight: drawData.lineHeight || 10,
								lineWidth: drawData.type === 'arc' ?
									0 // 弧线宽度后续可计算
									:
									Math.round(distance(drawData.start, drawData.end) * this
										.gridSize),
								idx: this.sureRoom[0].length + 1,
							});
							
						} else if (group.drawType === 2 || group.drawType === 3) {
							// 门（单开门或双开门）
							this.doors.push({
								...drawData,
								type: group.drawType === 2 ? 1 : 2,
								width: drawData.width || (group.drawType === 2 ? 20 : 40),
								rotateDeg: drawData.rotateDeg || 0,
								idx: this.doors.length,
								class: 'door',
							});
						} else if (group.drawType === 6) {
							// 窗户
							this.windows.push({
								...drawData,
								width: drawData.width || 40,
								height: drawData.height || 10,
								rotateDeg: drawData.rotateDeg || 0,
								idx: this.windows.length,
								class: 'window',
							});
						} else if (group.drawType === 4 || group.drawType === 5) {
							// 柱子（方柱或圆柱）
							this.pillars.push({
								...drawData,
								type: group.drawType === 4 ? 1 : 2,
								width: drawData.width || 40,
								height: drawData.height || (group.drawType === 4 ? 40 : null),
								rotateDeg: drawData.rotateDeg || 0,
								idx: this.pillars.length,
								class: 'pillar',
							});
						}
					});
				});

				console.log('页面数据已重新组织:', {
					sureRoom: this.sureRoom,
					doors: this.doors,
					windows: this.windows,
					pillars: this.pillars,
				});
				this.$nextTick(() => {
					that.drawAll();
				})
			},
			getData(id) {
				let that = this
				uni.request({
					url: `https://cad.hxjykt.com/cl/cad/${id}`,
					method: 'GET',
					success: res => {
						if (res.data.data) {
							this.defaultData = res.data.data;
							// const sureRoomList = this.defaultData.drawCadInfos
							// 	.find(item => item.drawType === 1)
							// 	?.drawCadDetails.map(item => {
							// 		item.drawStr = JSON.parse(item.drawStr)
							// 		const line = {
							// 			...item,
							// 			drawStr: item.drawStr,
							// 			start: snapToGrid.call(this, item.drawStr.start.x, item.drawStr
							// 				.start.y),
							// 			end: snapToGrid.call(this, item.drawStr.end.x, item.drawStr.end
							// 				.y),
							// 			type: 'line',
							// 			lineHeight: item.width,
							// 			lineWidth: distance(
							// 				snapToGrid.call(this, item.drawStr.start.x, item
							// 					.drawStr.start.y),
							// 				snapToGrid.call(this, item.drawStr.end.x, item.drawStr
							// 					.end.y)
							// 			) * this.gridSize * 10, // 存储为毫米
							// 			idx: this.sureRoom[0]?.length + 1 || 1,
							// 		};
							// 		return line;
							// 	});
							// this.sureRoom[0] = sureRoomList;
							// const singleDoor = this.defaultData.drawCadInfos
							// 	.find(item => item.drawType === 2)
							// 	.drawCadDetails.map(item => ({
							// 		...item,
							// 		type: 1
							// 	}));
							// const doubleDoor = this.defaultData.drawCadInfos
							// 	.find(item => item.drawType === 3)
							// 	.drawCadDetails.map(item => ({
							// 		...item,
							// 		type: 2
							// 	}));
							// this.doors = [...singleDoor, ...doubleDoor].map((item, idx) => ({
							// 	...item,
							// 	width: item.type === 1 ? item.radius : item.radius * 2,
							// 	pos: snapToGrid.call(this, item.x, item.y),
							// 	rotateDeg: 360 - item.rotationDirection,
							// 	idx,
							// 	class: 'door',
							// }));
							// const windowGroup = this.defaultData.drawCadInfos.find(item => item.drawType === 6)
							// 	.drawCadDetails;
							// this.windows = windowGroup.map((item, idx) => ({
							// 	type: 1,
							// 	name: '普通窗',
							// 	width: item.width,
							// 	height: item.height,
							// 	pos: snapToGrid.call(this, item.x, item.y),
							// 	idx,
							// 	class: 'window',
							// }));
							// const rectPillar = this.defaultData.drawCadInfos
							// 	.find(item => item.drawType === 4)
							// 	.drawCadDetails.map(item => ({
							// 		...item,
							// 		type: 1
							// 	}));
							// const cirPillar = this.defaultData.drawCadInfos
							// 	.find(item => item.drawType === 5)
							// 	.drawCadDetails.map(item => ({
							// 		...item,
							// 		type: 2
							// 	}));
							// this.pillars = [...rectPillar, ...cirPillar].map((item, idx) => ({
							// 	...item,
							// 	width: item.type === 1 ? item.width : item.radius * 2,
							// 	height: item.type === 1 ? item.height : null,
							// 	idx,
							// 	pos: snapToGrid.call(this, item.x, item.y),
							// 	class: 'pillar',
							// }));
							this.reorganizeData()
							
						}
					},
				});
			},
			getVisualAngle(cx, cy, px, py) {
				const dx = px - cx;
				const dy = py - cy;
				let angle = Math.atan2(-dy, dx) * 180 / Math.PI; // 视觉坐标系
				if (angle < 0) angle += 360;
				return angle;
			},

			// 对每条子弧线

			// getData(id) {
			//       uni.request({
			//         url: `http://120.76.159.210:9439/cl/cad/${id}`,
			//         method: 'GET',
			//         success: res => {
			//           if (res.data.data) {
			//             this.defaultData = res.data.data;
			//             const sureRoomList = this.defaultData.drawCadInfos
			//               .find(item => item.drawType === 1)
			//               ?.drawCadDetails.map(item => {
			//                 const line = {
			//                   ...item,
			//                   drawStr: JSON.parse(item.drawStr),
			//                   start: snapToGrid.call(this, item.drawStr.start.x, item.drawStr.start.y),
			//                   end: snapToGrid.call(this, item.drawStr.end.x, item.drawStr.end.y),
			//                   type: 'line',
			//                   lineHeight: item.width, // 厘米
			//                   lineWidth: distance(
			//                     snapToGrid.call(this, item.drawStr.start.x, item.drawStr.start.y),
			//                     snapToGrid.call(this, item.drawStr.end.x, item.drawStr.end.y)
			//                   ) * this.gridSize, // 厘米
			//                   idx: this.sureRoom[0]?.length + 1 || 1,
			//                 };
			//                 return line;
			//               });
			//             this.sureRoom[0] = sureRoomList;
			//             const singleDoor = this.defaultData.drawCadInfos
			//               .find(item => item.drawType === 2)
			//               .drawCadDetails.map(item => ({
			//                 ...item,
			//                 type: 1
			//               }));
			//             const doubleDoor = this.defaultData.drawCadInfos
			//               .find(item => item.drawType === 3)
			//               .drawCadDetails.map(item => ({
			//                 ...item,
			//                 type: 2
			//               }));
			//             this.doors = [...singleDoor, ...doubleDoor].map((item, idx) => ({
			//               ...item,
			//               width: item.type === 1 ? item.radius : item.radius * 2, // 厘米
			//               pos: snapToGrid.call(this, item.x, item.y),
			//               rotateDeg: 360 - item.rotationDirection,
			//               idx,
			//               class: 'door',
			//             }));
			//             const windowGroup = this.defaultData.drawCadInfos.find(item => item.drawType === 6)
			//               .drawCadDetails;
			//             this.windows = windowGroup.map((item, idx) => ({
			//               type: 1,
			//               name: '普通窗',
			//               width: item.width, // 厘米
			//               height: item.height, // 厘米
			//               pos: snapToGrid.call(this, item.x, item.y),
			//               idx,
			//               class: 'window',
			//             }));
			//             const rectPillar = this.defaultData.drawCadInfos
			//               .find(item => item.drawType === 4)
			//               .drawCadDetails.map(item => ({
			//                 ...item,
			//                 type: 1
			//               }));
			//             const cirPillar = this.defaultData.drawCadInfos
			//               .find(item => item.drawType === 5)
			//               .drawCadDetails.map(item => ({
			//                 ...item,
			//                 type: 2
			//               }));
			//             this.pillars = [...rectPillar, ...cirPillar].map((item, idx) => ({
			//               ...item,
			//               width: item.type === 1 ? item.width : item.radius * 2, // 厘米
			//               height: item.type === 1 ? item.height : null, // 厘米
			//               idx,
			//               pos: snapToGrid.call(this, item.x, item.y),
			//               class: 'pillar',
			//             }));
			//             this.drawAll();
			//           }
			//         },
			//       });
			//     },

			// // 计算封闭图形面积

			calculateCentroid(lines) {
				let xSum = 0;
				let ySum = 0;
				let area = 0;
				const n = lines.length;

				for (let i = 0; i < n; i++) {
					const j = (i + 1) % n;
					const factor = lines[i].start.x * lines[j].start.y - lines[j].start.x * lines[i].start.y;
					area += factor;
					xSum += (lines[i].start.x + lines[j].start.x) * factor;
					ySum += (lines[i].start.y + lines[j].start.y) * factor;
				}

				area /= 2;
				const centroidX = xSum / (6 * area);
				const centroidY = ySum / (6 * area);

				return {
					x: centroidX,
					y: centroidY
				};
			},
			copyItem() {
				if (!this.selectData || !this.selectData.class) return;
				this.saveState();
				// 计算偏移量并复制组件
				let offsetX, offsetY;
				const scalePix = this.gridSize / 10;
				const width = (this.selectData.width || 20) * scalePix;
				const offsetDistance = width * 1.5;

				if (this.selectData.rotateDeg) {
					const angle = (this.selectData.rotateDeg * Math.PI) / 180;
					offsetX = Math.cos(angle) * offsetDistance;
					offsetY = Math.sin(angle) * offsetDistance;
				} else {
					offsetX = offsetDistance;
					offsetY = 0;
				}

				const newItem = {
					...this.selectData,
					idx: this[this.selectData.class + 's'].length,
					pos: {
						x: this.selectData.pos.x + offsetX,
						y: this.selectData.pos.y + offsetY
					}
				};

				this[this.selectData.class + 's'].push(newItem);

				// ✅ 确保数据变更后再保存状态


				this.drawAll();
				uni.showToast({
					title: '复制成功',
					icon: 'success'
				});
			},
			deleteItem() {
				if (!this.selectData) return;
				this.saveState()
				if (this.selectData.type === 'line' || this.selectData.type === 'arc') {
					// 删除墙体
					this.sureRoom = this.sureRoom.map(room =>
						room.filter(line => line.idx !== this.selectData.idx)
					).filter(room => room.length > 0); // 移除空房间
				} else if (this.selectData.class) {
					// 删除门、窗、柱
					const targetArray = this[this.selectData.class + 's'];
					const index = targetArray.findIndex(item => item.idx === this.selectData.idx);
					if (index !== -1) {
						targetArray.splice(index, 1);
						// 重新分配索引以保持连续
						targetArray.forEach((item, idx) => {
							item.idx = idx;
						});
					}
				}

				// 清理选择状态
				this.selectData = null;
				this.selectedLine = null;
				this.modMainData = null;
				this.drawAll();
				uni.showToast({
					title: '删除成功',
					icon: 'success'
				});
			},
			getRotatedBottomLeftCorner(item) {
				const {
					pos,
					width,
					height,
					rotateDeg = 0
				} = item;
				const angle = (rotateDeg * Math.PI) / 180;
				const cos = Math.cos(angle);
				const sin = Math.sin(angle);

				// 原始左下角（未旋转）
				const localBL = {
					x: -width / 2,
					y: -height / 2
				};

				// 旋转后的偏移
				const rotatedX = localBL.x * cos - localBL.y * sin;
				const rotatedY = localBL.x * sin + localBL.y * cos;

				return {
					x: pos.x + rotatedX,
					y: pos.y + rotatedY
				};
			},



			getWallVertices(line) {
				const {
					start,
					end,
					lineHeight
				} = line;
				const wallThickness = lineHeight / 10 * this.gridSize; // 墙厚（单位：网格）

				const dx = end.x - start.x;
				const dy = end.y - start.y;
				const length = Math.sqrt(dx * dx + dy * dy);
				if (length === 0) return null;

				// 单位法向量
				const nx = -dy / length;
				const ny = dx / length;

				// 法向量乘以半个墙厚
				const offsetX = nx * wallThickness / 2;
				const offsetY = ny * wallThickness / 2;

				// 四个顶点：起始上、起始下、结束下、结束上
				const vertices = [{
						x: start.x + offsetX,
						y: start.y + offsetY
					}, // 起始点上方
					{
						x: start.x - offsetX,
						y: start.y - offsetY
					}, // 起始点下方
					{
						x: end.x - offsetX,
						y: end.y - offsetY
					}, // 结束点下方
					{
						x: end.x + offsetX,
						y: end.y + offsetY
					} // 结束点上方
				];

				return vertices;
			},
			// 视觉坐标系：正右 0°，逆时针为正
			getStartAngle(start, center) {
				const dx = start.x - center.x;
				const dy = start.y - center.y;
				let angle = Math.atan2(-dy, dx) * 180 / Math.PI; // -dy 让 Y 轴向下为正
				if (angle < 0) angle += 360;
				return Math.round(angle);
			},

			// 返回弧线外接矩形 + 角度信息（用于 subData）
			getArcInfoForDXF(line) {
				const {
					start,
					end,
					controlPoint
				} = line;

				// 1. 角度部分——你原逻辑，一字不改
				const center = {
					x: (start.x + end.x) / 2,
					y: (start.y + end.y) / 2
				};
				const radius = Math.hypot(start.x - center.x, start.y - center.y);
				const startAngle = this.getStartAngle(start, center);
				const endAngle = this.getStartAngle(end, center);
				let arcAngle = endAngle - startAngle;
				if (arcAngle <= 0) arcAngle += 360;

				// 2. 弦中点
				const vertex = {
					x: 0.25 * start.x + 0.5 * controlPoint.x + 0.25 * end.x,
					y: 0.25 * start.y + 0.5 * controlPoint.y + 0.25 * end.y
				};

				// 4. 弦中点
				const midChord = {
					x: (start.x + end.x) / 2,
					y: (start.y + end.y) / 2
				};
				// 4. 弦方向
				const dxChord = end.x - start.x;
				const dyChord = end.y - start.y;
				// 5. 顶点距离
				const vertexDist = Math.hypot(vertex.x - midChord.x, vertex.y - midChord.y);

				// 6. 外接矩形
				let rectWidth = Math.abs(dxChord);
				let rectHeight = Math.abs(dyChord);

				if (Math.abs(dyChord) < Math.abs(dxChord)) {
					// 水平弧——高度由顶点决定
					rectHeight = vertexDist * 2;
				} else {
					// 垂直弧——宽度由顶点决定
					rectWidth = vertexDist * 2;
				}

				return {
					x: Math.min(start.x, end.x) - (rectWidth - Math.abs(dxChord)) / 2,
					y: Math.min(start.y, end.y) - (rectHeight - Math.abs(dyChord)) / 2,
					rectWidth,
					rectHeight,
					startAngle: Math.round(startAngle),
					arcAngle: Math.round(arcAngle)
				};
			},
			getStartAngle(start, center) {
				const dx = start.x - center.x;
				const dy = start.y - center.y;
				let angle = Math.atan2(-dy, dx) * 180 / Math.PI; // 视觉坐标系
				if (angle < 0) angle += 360;
				return angle;
			},
			getArcOffsetLinesByDistance(arcLine, offsetWorld) {
				const {
					start,
					end,
					controlPoint
				} = arcLine;

				// 1. 弦中点
				const midChord = {
					x: (start.x + end.x) / 2,
					y: (start.y + end.y) / 2
				};

				// 2. 当前顶点偏移向量
				const dxControl = controlPoint.x - midChord.x;
				const dyControl = controlPoint.y - midChord.y;

				// 3. 单位化
				const lenControl = Math.hypot(dxControl, dyControl) || 1;
				const ux = dxControl / lenControl;
				const uy = dyControl / lenControl;

				// 4. 内弧/外弧 controlPoint 沿弯曲方向推拉
				const innerControl = {
					x: controlPoint.x - ux * offsetWorld,
					y: controlPoint.y - uy * offsetWorld,
				};
				const outerControl = {
					x: controlPoint.x + ux * offsetWorld,
					y: controlPoint.y + uy * offsetWorld,
				};

				// 5. 起点/终点仍平行偏移（保持闭合）
				const dx = end.x - start.x;
				const dy = end.y - start.y;
				const len = Math.hypot(dx, dy) || 1;
				const nx = -dy / len;
				const ny = dx / len;
				const ox = nx * offsetWorld;
				const oy = ny * offsetWorld;

				return [{
						start: {
							x: start.x - ox,
							y: start.y - oy
						},
						end: {
							x: end.x - ox,
							y: end.y - oy
						},
						controlPoint: innerControl,
					},
					{
						start: {
							x: start.x + ox,
							y: start.y + oy
						},
						end: {
							x: end.x + ox,
							y: end.y + oy
						},
						controlPoint: outerControl,
					},
				];
			},
			// 绕点旋转坐标点
			rotatePoint(point, center, angleDeg) {
				const angleRad = (angleDeg * Math.PI) / 180;
				const cos = Math.cos(angleRad);
				const sin = Math.sin(angleRad);
				const dx = point.x - center.x;
				const dy = point.y - center.y;
				return {
					x: center.x + dx * cos - dy * sin,
					y: center.y + dx * sin + dy * cos
				};
			},

			// 获取将线段旋转到水平或垂直所需的角度（逆时针为正）
			getRotationAngleToAlign(start, end) {
				const dx = end.x - start.x;
				const dy = end.y - start.y;
				let angle = Math.atan2(dy, dx) * 180 / Math.PI; // 与 X 轴夹角
				if (angle < 0) angle += 360;

				// 找到最近的水平或垂直方向
				const candidates = [0, 90, 180, 270];
				let minDiff = Infinity;
				let targetAngle = 0;
				for (const cand of candidates) {
					let diff = Math.abs(angle - cand);
					if (diff > 180) diff = 360 - diff;
					if (diff < minDiff) {
						minDiff = diff;
						targetAngle = cand;
					}
				}

				// 返回需要旋转的角度（逆时针为正）
				return targetAngle - angle;
			},
			subData() {

				const that = this
				if (!this.sureRoom || !this.sureRoom.length) return;
				const {
					area
				} = this.calculatePolygonArea(this.sureRoom[0]);
				const centroid = this.calculateCentroid(this.sureRoom[0]);

				const natArea = area;
				const subParams = {
					name: new Date().getTime(),
					userId: 111111,
					areaNum: area,
					x: centroid.x||0,
					y: centroid.y||0,
					info: [{
							drawType: 1,
							drawInfos: this.sureRoom[0]?.map(item => {
								const po = that.getWallVertices(item)
								let xys
								let rotateAngle = 0
								if (item.type === 'arc') {
									const start = item.start;
									const end = item.end;
									const control = item.controlPoint;

									// 计算旋转角度
									rotateAngle = this.getRotationAngleToAlign(start, end);

									// 构造旋转后的弧线
									const rotatedEnd = this.rotatePoint(end, start, rotateAngle);
									const rotatedControl = this.rotatePoint(control, start, rotateAngle);
									const rotatedArc = {
										start: start,
										end: rotatedEnd,
										controlPoint: rotatedControl,
										lineHeight: item.lineHeight
									};

									// 沿用你已有方法
									const offsetWorld = item.lineHeight / 10 * this.gridSize / 2;
									const [innerArc, outerArc] = this.getArcOffsetLinesByDistance(
										rotatedArc, offsetWorld);
									const innerXys = this.getArcInfoForDXF(innerArc);
									const outerXys = this.getArcInfoForDXF(outerArc);

									// 修正外接矩形（你原来的逻辑）
									const t = item.lineHeight;
									outerXys.rectWidth += t * 2;
									outerXys.rectHeight += t * 2;
									outerXys.x = innerXys.x - t;
									outerXys.y = innerXys.y - t;

									xys = [innerXys, outerXys];
								} else {
									xys = po.map(item => {
										return {
											...item,
											startAngle: null,
											arcAngle: null,
											rectWidth: null,
											rectHeight: null,
											radius: null
										}
									})
								}
								return {
									xys: xys,
									drawStr: JSON.stringify(item),
									wallType: item.wallType,
									type: item.type == 'arc' ? 2 : 1,
									areaNum: null,
									floorCount: null,
									bevelArc: 360 - rotateAngle,
									floorArea: null
								}
								// const worldPosStart = worldToScreen.call(this, item.start);
								// const worldPosEnd = worldToScreen.call(this, item.end);
								// return {
								// 	wallType: item.wallType || (worldPosStart.y === worldPosEnd.y ? 2 : 1),
								// 	drawStr: JSON.stringify({
								// 		start: item.start,
								// 		end: item.end,
								// 		controlPoint: item.controlPoint
								// 	}),
								// 	x: Math.min(worldPosStart.x, worldPosEnd.x),
								// 	y: Math.min(worldPosStart.y, worldPosEnd.y),
								// 	height: item.lineWidth / 10, // 转换为厘米
								// 	width: item.lineHeight,
								// 	radius: 0,
								// 	angle: 0,
								// 	areaNum: 0,
								// 	floorCount: 0,
								// 	floorArea: 0,
								// };
							}),
						},
						{
							drawType: 2,
							drawInfos: this.doors
								.filter(item => item.type === 1)
								.map(item => {
									// const worldPosStart = worldToScreen.call(this, item.pos);
									return {
										xys: [{
											x: item.pos.x,
											y: item.pos.y,
											startAngle: 360 - (item.rotateDeg || 0),
											arcAngle: 90,
											rectWidth: null,
											rectHeight: null,
											radius: item.width
										}],
										drawStr: JSON.stringify(item),
										wallType: 0,
										type: 0,
										areaNum: null,
										floorCount: null,
										floorArea: null
									}
									// return {
									// 	x: worldPosStart.x,
									// 	y: worldPosStart.y,
									// 	height: item.width,
									// 	width: 0,
									// 	radius: item.width,
									// 	angle: 90,
									// 	rotationDirection: 360 - (item.rotateDeg || 0),
									// 	areaNum: 0,
									// 	floorCount: 0,
									// 	floorArea: 0,
									// };
								}),
						},
						{
							drawType: 3,
							drawInfos: this.doors
								.filter(item => item.type === 2)
								.map(item => {
									let obj = {
										xys: [{
											x: item.pos.x,
											y: item.pos.y,
											startAngle: 360 - (item.rotateDeg || 0),
											arcAngle: 90,
											rectWidth: null,
											rectHeight: null,
											radius: item.width / 2
										}],
										drawStr: JSON.stringify(item),
										wallType: 0,
										type: 0,
										areaNum: null,
										floorCount: null,
										floorArea: null
										// const worldPosStart = worldToScreen.call(this, item.pos);
										// let obj = {
										// 	x: worldPosStart.x,
										// 	y: worldPosStart.y,
										// 	height: item.width / 2,
										// 	width: 0,
										// 	radius: item.width / 2,
										// 	areaNum: 0,
										// 	floorCount: 0,
										// 	floorArea: 0,
										// };
									}
									if (!item.rotateDeg || item.rotateDeg === 360) {
										obj.xys[0].arcAngle = 360;
										obj.xys[0].startAngle = 90;
										// obj.x += item.width / 2;
									} else if (item.rotateDeg === 90) {
										obj.xys[0].arcAngle = 270;
										obj.xys[0].startAngle = 360;
										// obj.x += item.width / 2;
									} else if (item.rotateDeg === 180) {
										obj.xys[0].arcAngle = 270;
										obj.xys[0].startAngle = 180;
										// obj.x += item.width / 2;
									} else {
										obj.xys[0].arcAngle = 180;
										obj.xys[0].startAngle = 90;
										// obj.x -= item.width / 2;
									}
									return obj;
								}),
						},
						{
							drawType: 6,
							drawInfos: this.windows.map(item => {
								const corner = this.getRotatedBottomLeftCorner(item);
								const x = corner.x;
								const y = corner.y;
								return {
									xys: [{
										x: x,
										y: y,
										startAngle: 360 - (item.rotateDeg || 0),
										arcAngle: 90,
										rectWidth: item.width,
										rectHeight: item.height,
										radius: null
									}],
									drawStr: JSON.stringify(item),
									wallType: 0,
									type: 0,
									areaNum: null,
									floorCount: null,
									floorArea: null

								};
							}),
						},
						{
							drawType: 4,
							drawInfos: this.pillars
								.filter(item => item.type === 1)
								.map(item => {
									const corner = this.getRotatedBottomLeftCorner(item);
									const x = corner.x;
									const y = corner.y;
									return {
										xys: [{
											x: x,
											y: y,
											startAngle: 360 - (item.rotateDeg || 0),
											arcAngle: null,
											rectWidth: item.width,
											rectHeight: item.height,
											radius: null
										}],
										drawStr: JSON.stringify(item),
										wallType: 0,
										type: 0,
										areaNum: null,
										floorCount: null,
										floorArea: null
									};
								}),
						},
						{
							drawType: 5,
							drawInfos: this.pillars
								.filter(item => item.type === 2)
								.map(item => {
									// const worldPosStart = worldToScreen.call(this, item.pos);
									return {

										xys: [{
											x: item.pos.x,
											y: item.pos.y,
											startAngle: 360 - (item.rotateDeg || 0),
											arcAngle: null,
											rectWidth: null,
											rectHeight: null,
											radius: item.width / 2
										}],
										drawStr: JSON.stringify(item),
										wallType: 0,
										type: 0,
										areaNum: null,
										floorCount: null,
										floorArea: null
									};
								}),
						},
					]
				};
				console.log(subParams)
				
				// // #ifdef APP-PLUS
				// // const url = 
				// uni.request({
				// 	url: this.defaultData ? `http://120.76.159.210:9439/cl/cad/save/${this.defaultData.id}` :
				// 	`http://120.76.159.210:94390/cl/cad/save`,
				// 	method: this.defaultData ? 'PUT' : 'POST',
				// 	data: subParams,
				// 	success: res => {
				// 		console.log(res,1)
				// 		uni.showToast({
				// 			title: '提交成功',
				// 			icon: 'success'
				// 		});
				// 	},
				// 	fail: err => {
				// 		console.log(1)
				// 		uni.showToast({
				// 			title: '提交失败',
				// 			icon: 'none'
				// 		});
				// 	},
				// });
							
				// // #endif
				// const url = 
				uni.request({
					url: this.defaultData ? `https://cad.hxjykt.com/cl/cad/edit/${this.defaultData.id}` :
					`https://cad.hxjykt.com/cl/cad/save`,
					method: this.defaultData ? 'PUT' : 'POST',
					data: subParams,
					success: res => {
						console.log(res,'2')
						this.defaultData = res.data.data
						uni.showToast({
							title: '提交成功',
							icon: 'success'
						});
					},
					fail: err => {
						console.log(2)
						uni.showToast({
							title: '提交失败',
							icon: 'none'
						});
					},
				});
				
			},
			exportData() {
				uni.request({

					url: `https://cad.hxjykt.com/cl/cad/dxf/${this.defaultData.id}`,
					method: 'GET',
					success: res => {
						console.log(res)
						uni.downloadFile({
							// url: `http://yypt.hxjykt.com/cad/dxf/${this.defaultData.id}.dxf`,
							url: res.data.data,
							success: res => {
								uni.openDocument({
									filePath: res.tempFilePath,
									fileType: 'other',
									success: () => {
										uni.showToast({
											title: '文件已打开',
											icon: 'success'
										});
									},
									fail: err => {
										uni.showToast({
											title: '打开失败',
											icon: 'none'
										});
									},
								});
							},
						});
					},
				});
			},
		},
	};
</script>

<style lang="scss">
  .engineering-canvas {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    overflow: hidden;
    touch-action: none;
    height: 100%;
    z-index: 0;
  }

  .canvas-layer {
    position: absolute;
    width: 100vw;
    height: 100vh;
    z-index: 1;
    background-color: #f9f9f9;
  }

  .control-buttons {
    position: absolute;
    right: 10rpx;
    top: 10rpx;
    z-index: 100;
    display: flex;
    flex-direction: column;
  }

  .btn {
    margin-bottom: 10rpx;
    padding: 10rpx 20rpx;
    background: orange;
    color: #fff;
    border-radius: 10rpx;
    text-align: center;
  }

  .btn-active {
    background: #ff4500;
  }

  .close-btn {
    position: fixed;
    bottom: 300rpx;
    right: 50rpx;
    width: 100rpx;
    height: 100rpx;
    line-height: 100rpx;
    border-radius: 50%;
    text-align: center;
    background: orange;
    color: #fff;
    font-size: 32rpx;
    z-index: 10;
    box-shadow: 0 4rpx 8rpx rgba(0, 0, 0, 0.2);
  }

  .data-operate {
    position: absolute;
    right: 20rpx;
    top: 220rpx;
    background: rgba(0, 0, 0, 0.5);
    z-index: 10;
    padding: 10rpx;
    border-radius: 20rpx;
  }

  .ope {
    display: flex;
    flex-direction: column;
    align-items: center;
    font-size: 24rpx;
    color: #fff;
    margin-bottom: 20rpx;
  }

  .ope-icon {
    width: 60rpx;
    height: 60rpx;
	image{
		width:100%;
		height:100%
	}
  }

  .ope-name {
    margin-top: 5rpx;
  }

  .data-main-set {
    position: absolute;
    bottom: 0;
    width: 100%;
    z-index: 13;
    padding: 30rpx 0 0;
    background: #fff;
    border-radius: 20rpx 20rpx 0 0;
    box-shadow: 0px 0px 12rpx 0px #e3e5e8;
  }

  .status-type-list {
    display: flex;
  }

  .single-status {
    margin: 0 40rpx 40rpx;
  }

  .status-active {
    color: orange;
  }

  .wall-thick {
    padding: 10rpx 0 0;
    width: 100%;
    background: #ccc;
  }

  .wall-thick-input {
    width: 100%;
    padding: 20rpx;
    box-sizing: border-box;
    border: 1rpx solid #ccc;
    border-radius: 10rpx;
    display: flex;
    justify-content: space-between;
    background: #fff;
  }

  .wall-thick-calendar {
    display: flex;
    justify-content: space-between;
    background: #ccc;
  }

  .cal-num {
    width: 500rpx;
    display: flex;
    justify-content: flex-start;
    flex-wrap: wrap;
  }

  .single-num {
    width: 33%;
    padding: 10rpx;
    box-sizing: border-box;
    text-align: center;
  }

  .cal-confirm {
    flex: 1;
    height: 470rpx;
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
  }

  .cal-del,
  .cal-sure {
    padding: 10rpx;
    box-sizing: border-box;
  }

  .cal-sure {
    flex: 1;
  }

  .cal-btn {
    padding: 10rpx;
    background: #fff;
    height: 80rpx;
    line-height: 80rpx;
    border-radius: 10rpx;
    display: flex;
    align-items: center;
    justify-content: center;
	image{
		width:100%
	}
  }

  .full-cal {
    width: 100%;
  }

  .wall-list {
    display: flex;
    justify-content: flex-start;
    flex-wrap: wrap;
  }

  .wall {
    width: 25%;
    padding: 10rpx;
    box-sizing: border-box;
    position: relative;
  }

  .wallPic {
    width: 100%;
    height: 100rpx;
  }

  .selected-wall {
    position: absolute;
    right: 0;
    top: 0;
    width: 30rpx;
    height: 30rpx;
  }

  .wallDesc {
    text-align: center;
  }

  .active-wall {
    border: 1rpx solid #ccc;
  }

  .bot-btn-list {
    width: 100%;
    position: absolute;
    bottom: 50rpx;
    display: flex;
    align-items: flex-start;
    justify-content: flex-end;
    z-index: 9;
  }

  .bot-btn {
    width: 25%;
    display: flex;
    flex-direction: column;
    align-items: center;
    font-size: 16rpx;
	image{
		width:100%
	}
  }

  .btn-icon {
    width: 100rpx;
    height: 100rpx;
    border-radius: 50%;
    margin-bottom: 16rpx;
  }

  .add-item-list {
    position: absolute;
    bottom: 0;
    width: 100%;
    background: #fff;
    box-sizing: border-box;
    z-index: 100;
    padding: 50rpx 0 30rpx 0;
    border-radius: 20rpx 20rpx 0 0;
    box-shadow: 0px 0px 12rpx 0px #e3e5e8;
  }

  .tab-scroll {
    width: 100%;
    margin-bottom: 20rpx;
  }

  .tab-list {
    width: 100%;
    display: flex;
    padding: 0 50rpx;
  }

  .tab-item {
    white-space: nowrap;
    margin-right: 30rpx;
  }

  .active-item {
    color: orange;
    position: relative;
  }

  .active-item:after {
    content: '';
    display: block;
    width: 100%;
    height: 1rpx;
    background: orange;
    left: 0;
    bottom: -20rpx;
  }

  .tab-item-main {
    display: flex;
    justify-content: flex-start;
    flex-wrap: wrap;
    padding: 0 50rpx;
	width:100%;
  }

  .add-item {
    display: flex;
    width: 25%;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 10rpx;
	
  }

  .add-inner {
    background: rgb(241, 241, 239);
    padding-bottom: 10rpx;
	width:100%;
	height:100%;
	image{
		width:100%
	}
  }

  .add-item-icon {
    width: 100%;
    padding: 10rpx 10rpx 0;
    box-sizing: border-box;
  }

  .add-item-name {
    box-sizing: border-box;
    text-align: center;
    width: 100%;
  }
</style>